/*-------------------------------------------------------------------------------
Copyright (c)2000 TogetherSoft Corporation. Patents pending. All rights reserved.
-------------------------------------------------------------------------------*/

package com.togethersoft.modules.tutorial;

import com.togethersoft.openapi.ide.IdeContext;
import com.togethersoft.openapi.ide.IdeScript;
import com.togethersoft.openapi.ide.message.IdeMessageManager;
import com.togethersoft.openapi.ide.message.IdeMessageManagerAccess;
import com.togethersoft.openapi.ide.message.IdeMessagePage;
import com.togethersoft.openapi.ide.window.IdeDialogType;
import com.togethersoft.openapi.ide.window.IdeWindowManager;
import com.togethersoft.openapi.ide.window.IdeWindowManagerAccess;
import com.togethersoft.openapi.ide.message.IdeMessageType;
import com.togethersoft.openapi.ide.project.IdeProjectManagerAccess;
import com.togethersoft.openapi.rwi.RwiVisitorAdapter;
import com.togethersoft.openapi.rwi.RwiNode;
import com.togethersoft.openapi.rwi.RwiMember;
import com.togethersoft.openapi.rwi.RwiLink;
import com.togethersoft.openapi.rwi.RwiDiagram;
import com.togethersoft.openapi.rwi.RwiPropertyMap;
import com.togethersoft.openapi.rwi.RwiPackage;
import com.togethersoft.openapi.rwi.RwiProperty;
import com.togethersoft.openapi.rwi.RwiElement;
import com.togethersoft.openapi.rwi.RwiVisitor;
import com.togethersoft.openapi.rwi.RwiReference;
import com.togethersoft.openapi.rwi.enum.RwiNodeEnumeration;
import com.togethersoft.openapi.rwi.enum.RwiDiagramEnumeration;
import com.togethersoft.openapi.rwi.enum.RwiReferenceEnumeration;
import com.togethersoft.openapi.rwi.enum.RwiPackageEnumeration;
import com.togethersoft.openapi.rwi.enum.RwiPropertyEnumeration;
import java.util.Vector;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JTree;
import javax.swing.JScrollPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;

/**
 * This module illustrates how to work with the element's properties.
 * It iterates the selection, extracts information about elements and builds
 * a tree with this information.
 *
 * Also it shows the usage of RwiVisitor interface. The module just invokes
 * the accept (RwiVisitor) method upon each element in the selection.
 * Accept method automatically runs method from RwiVisitor corresponding to
 * the kind of the element.
 * The visitor's method returns Object which is a DefaultMutableNode in our case
 * with an appropriate information. This node is then added to the root node of
 * the tree.
 * See details about RwiVisitor and other interfaces in the main API docs.
 *
 * Important: select a package in a diagram, then run this module.
 * The module reports that you have selected a diagram, not a package
 * as you might expect!
 * See details about this in the RwiDiagram interface description.
 *
 * @author TogetherSoft
 */
public class Lesson03 implements IdeScript
{
   /**
    * Runs this module.
    *
    * @param context the IdeContext instance containing
    * the selection information at the moment the module was called.
    */
    public void run(IdeContext context)
    {
        // printing information message
        IdeMessageManagerAccess.printMessage
            (IdeMessageType.INFORMATION, "Lesson03 module: started");

        // checking if project is open
        if (IdeProjectManagerAccess.getProjectManager().getActiveProject() == null)
        {
            // projects was not opened

            // open modal window with error description
            IdeMessageManagerAccess.printMessage
                (IdeMessageType.ERROR_MODAL, "No open project");
            // printing message into message pane
            IdeMessageManagerAccess.printMessage
                (IdeMessageType.INFORMATION, "Lesson03 module: finished");
            return;
        }

        // start work with the selection

        // getting array of selected RwiElements from context
        RwiElement[] selectedRwiElements = context.getRwiElements();

        // checking if array is empty
        if (selectedRwiElements == null || selectedRwiElements.length == 0)
        {
            // array is empty
            IdeMessageManagerAccess.printMessage
                (IdeMessageType.ERROR_MODAL, "No selection was made.");
            IdeMessageManagerAccess.printMessage
                (IdeMessageType.INFORMATION, "Lesson03 module: finished");
            return;
        }

        // new visitor
        RwiVisitor visitor = new SampleVisitor();

        // new tree node
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");

        // iterating the selection
        for (int i = 0; i < selectedRwiElements.length; i++)
        {
            // getting current element form array
            RwiElement rwiElement = selectedRwiElements[i];

            // calling visitor's visitXXX method corresponding
            // to the kind of the element
            DefaultMutableTreeNode node =
                (DefaultMutableTreeNode) rwiElement.accept(visitor);

            // adding node
            root.add(node);
        }

        // show dialog with element tree
        showDialog(root);

        // final message in message pane
        IdeMessageManagerAccess.printMessage
            (IdeMessageType.INFORMATION, "Lesson03 module: finished");
    }

    /**
    * Builds the tree and shows it in a standard dialog window.
    *
    * @param root DefaultMutableTreeNode object containing result of analisys
    */
    private void showDialog(DefaultMutableTreeNode root)
    {
        JTree tree = new JTree(root);
        tree.setRootVisible(false);
        tree.setCellRenderer(new MyCellRenderer());
        tree.setShowsRootHandles(true);
        JScrollPane info = new JScrollPane(tree);
        info.setPreferredSize(new Dimension(500, 300));
        // show result tree
        IdeWindowManagerAccess.getWindowManager().showMessageDialog
            ("Results", IdeDialogType.INFORMATION, info);
    }

    /**
     * This visitor is used to perform some sort of analisys for a given
     * RwiElement. Its methods behave very similar - they return a
     * DefaultMutableTreeNode object containing the results of analisys
     * appropriate for "acceptor" - RwiElement of this visitor.
     *
     * Note that unlike PropertiesVisitor (see below) the returned node contains
     * not only a set of existing RwiProperties the acceptor has (that node
     * is created by PropertiesVisitr), but other nodes - package, a desing package etc.
     * Each RwiElement has a different set of auxilairy nodes.
     */
    private class SampleVisitor extends RwiVisitorAdapter
    {
        /**
        * Returns a DefaultMutableTreeNode object for specified RWI node with next info:
        * 1. Properties of this RwiNode
        * 2. Its containing package's info.
        *
        * @param node RwiNode object
        * @return DefaultMutableTreeNode object
        */
        public Object visitNode(RwiNode node)
        {
            // properties of node
            DefaultMutableTreeNode root =
                new DefaultMutableTreeNode("RwiNode " + node.getProperty(RwiProperty.NAME));
            PrVisitr visitor = new PrVisitr();
            root.add((DefaultMutableTreeNode)node.accept(visitor));

            // containing package
            DefaultMutableTreeNode temp =
                new DefaultMutableTreeNode("Containing package");
            temp.add((DefaultMutableTreeNode)visitPackage(node.getContainingPackage()));
            root.add(temp);

            return root;
        }

        /**
        * Returns a DefaultMutableTreeNode object for specified RWI member
        * with next info:
        * 1. Properties of this RwiMember
        * 2. Its containing RwiNode's info
        *
        * @param member RwiMember object
        * @return DefaultMutableTreeNode object
        */
        public Object visitMember(RwiMember member)
        {
            // properties
            DefaultMutableTreeNode root =
                new DefaultMutableTreeNode("RwiMember " + member.getProperty(RwiProperty.NAME));
            PrVisitr visitor = new PrVisitr();
            root.add((DefaultMutableTreeNode)member.accept(visitor));

            // containing nodes
            DefaultMutableTreeNode temp =
                new DefaultMutableTreeNode("Containing RwiNode");
            temp.add((DefaultMutableTreeNode)visitNode(member.getContainingNode()));
            root.add(temp);

            return root;
        }

        /**
         * Returns a DefaultMutableTreeNode object for specified RWI diagram
         * with next info:
         * 1. Properties of this RwiDiagram
         * 2. RwiElements referenced from this RwiDiagram
         * 3. Its containing RwiPackage
         * 4. Its design RwiPackage (see RwiPackage description).
         *
         * @param diagram RwiDiagram object
         * @return DefaultMutableTreeNode object
         */
        public Object visitDiagram(RwiDiagram diagram)
        {
            // getting properties
            DefaultMutableTreeNode root =
                new DefaultMutableTreeNode("RwiDiagram " +
                diagram.getProperty(RwiProperty.NAME));
            PrVisitr visitor = new PrVisitr();
            root.add((DefaultMutableTreeNode)diagram.accept(visitor));

            // if physical package diagram
            if (diagram.hasProperty(RwiProperty.PHYSICAL_PACKAGE))
            {
                root.add(
                    new DefaultMutableTreeNode("it is a physical package diagram"));
                root.add(
                    new DefaultMutableTreeNode("reflectes a package (and is contained in): " +
                    diagram.getContainingPackage().getProperty(RwiProperty.FULL_NAME)));
            }

            // getting referenced nodes

            DefaultMutableTreeNode referencesNode =
                new DefaultMutableTreeNode("Contains RwiReferences to");

            // getting enumeration of all references
            RwiReferenceEnumeration refs = diagram.references();

            // processing all reference element
            while (refs.hasMoreElements())
            {
                RwiReference nextRef = refs.nextRwiReference();
                RwiElement refElement = nextRef.getElement();
                referencesNode.add(
                    new DefaultMutableTreeNode(refElement.getProperty(RwiProperty.FULL_NAME)));
            }
            root.add(referencesNode);

            // getting packages
            DefaultMutableTreeNode temp =
                new DefaultMutableTreeNode("Containing package");
            temp.add((DefaultMutableTreeNode)visitPackage(diagram.getContainingPackage()));
            root.add(temp);

            // if design package exists
            if (diagram.getDesignPackage() != null)
            {
                temp = new DefaultMutableTreeNode("Design package");
                temp.add((DefaultMutableTreeNode)visitPackage(diagram.getDesignPackage()));
                root.add(temp);
            }

            return root;
        }

        /**
         * Returns a DefaultMutableTreeNode object for specified RWI link
         * with next info:
         * 1. Properties of this RWI link
         * 2. Source of this RWI link
         * 3. Destination of this RWI link
         *
         * @param link RwiLink object
         * @return DefaultMutableTreeNode object
         */
        public Object visitLink(RwiLink link)
        {
            // getting properties
            DefaultMutableTreeNode root =
                new DefaultMutableTreeNode("RwiLink " + link.getProperty(RwiProperty.NAME));
            PrVisitr visitor = new PrVisitr();
            root.add((DefaultMutableTreeNode)link.accept(visitor));

            // getting source
            DefaultMutableTreeNode source =
                new DefaultMutableTreeNode("Source of this link");
            RwiElement sourceElement = link.getSource();
            source.add((DefaultMutableTreeNode)sourceElement.accept(visitor));
            root.add(source);

            // getting destination
            DefaultMutableTreeNode destination =
                new DefaultMutableTreeNode("Destination of this link");
            RwiElement destElement = link.getDestination();
            destination.add((DefaultMutableTreeNode)destElement.accept(visitor));
            root.add(destination);
            return root;
        }

        /**
         * Returns a DefaultMutableTreeNode object for specified RWI package
         * with next info:
         * 1. Properties of this Rwi package
         * 2. RwiNodes contained in it
         * 3. RwiDiagrams contained in it
         * 4. RwiPackages contained in it.
         *
         * Interesting: run this module for the root package.
         * Note that it has a lot of side package, they have the IMPORT or
         * COMPONENT property set to true. That is why we filter out them
         * using the hasProperty(RwiProperty.MODEL) call.
         *
         * @param rwiPackage RwiPackage object
         * @return DefaultMutableTreeNode object
         */
        public Object visitPackage(RwiPackage rwiPackage)
        {
            // getting properties
            DefaultMutableTreeNode root =
                new DefaultMutableTreeNode("RwiPackage " +
                rwiPackage.getProperty(RwiProperty.NAME));
            PrVisitr visitor = new PrVisitr();
            root.add((DefaultMutableTreeNode)rwiPackage.accept(visitor));

            // getting subnodes

            DefaultMutableTreeNode subnodesNode =
                new DefaultMutableTreeNode("Contains RwiNodes");

            // getting enumeration of all subnodes
            RwiNodeEnumeration subnodes = rwiPackage.nodes();

            // processing each subnode
            while (subnodes.hasMoreElements())
            {
                RwiNode nextSubnode = subnodes.nextRwiNode();
                DefaultMutableTreeNode childNode =
                    new DefaultMutableTreeNode("RwiNode " +
                    nextSubnode.getProperty(RwiProperty.NAME));
                childNode.add((DefaultMutableTreeNode)nextSubnode.accept(visitor));
                subnodesNode.add(childNode);
            }
            root.add(subnodesNode);

            // getting diagrams

            DefaultMutableTreeNode diagramsNode =
                new DefaultMutableTreeNode("Contains RwiDiagrams");

            // getting enumeration of all diagrams
            RwiDiagramEnumeration diagrams = rwiPackage.diagrams();

            // processing each diagram
            while (diagrams.hasMoreElements())
            {
                RwiDiagram nextDiagram = diagrams.nextRwiDiagram();
                DefaultMutableTreeNode childNode = new
                    DefaultMutableTreeNode("RwiDiagram " +
                    nextDiagram.getProperty(RwiProperty.NAME));
                childNode.add((DefaultMutableTreeNode)nextDiagram.accept(visitor));
                diagramsNode.add(childNode);
            }
            root.add(diagramsNode);

            // getting packages

            DefaultMutableTreeNode packagesNode =
                new DefaultMutableTreeNode("Contains RwiPackages");

            // getting enumeration of all subpackages
            RwiPackageEnumeration subpackages = rwiPackage.subpackages();

            // processing each package
            while (subpackages.hasMoreElements())
            {
                RwiPackage nextPackage = subpackages.nextRwiPackage();
                DefaultMutableTreeNode childNode =
                    new DefaultMutableTreeNode("RwiPackage " +
                    nextPackage.getProperty(RwiProperty.NAME));
                childNode.add((DefaultMutableTreeNode)nextPackage.accept(visitor));
                packagesNode.add(childNode);
            }
            root.add(packagesNode);

            return root;
        }
    }

    /**
     * Displays an entry in a tree.
     * @see javax.swing specification
     */
    private class MyCellRenderer extends DefaultTreeCellRenderer
    {
       public Component getTreeCellRendererComponent
       (JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
       {
            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
            setIcon(null);
            return this;
        }
    }

    /**
    * Properties visitor class.
    * This visitor does the same thing for all RwiElements -
    * it returns a DefaultMutableNode containing information about all non-null
    * or enabled boolean RwiProperties for the element.
    * This node can be used then somewhere to build a tree.
    * You can use this visitor in your modules (just cut it from here).
    * We don't make it public in this package in order to minimize the number
    * of files within this sample directory.
    */
    private class PrVisitr extends RwiVisitorAdapter
    {
        /**
         * Creates a default class instance.
         */
        public PrVisitr()
        {
            // creation new Vector object
            properties = new Vector();

            // adding proprties into Vector
            properties.addElement(new PropInfo(RwiProperty.ABSTRACT, "ABSTRACT"));
            properties.addElement(new PropInfo(RwiProperty.AGGREGATION, "AGGREGATION"));
            properties.addElement(new PropInfo(RwiProperty.ASSOCIATES, "ASSOCIATES", false));
            properties.addElement(new PropInfo(RwiProperty.BODY, "BODY", false));
            properties.addElement(new PropInfo(RwiProperty.BY_VALUE, "BY_VALUE"));
            properties.addElement(new PropInfo(RwiProperty.COMPILED, "COMPILED"));
            properties.addElement(new PropInfo(RwiProperty.COMPONENT, "COMPONENT"));
            properties.addElement(new PropInfo(RwiProperty.CONSTRUCTOR, "CONSTRUCTOR"));
            properties.addElement(new PropInfo(RwiProperty.DECLARATION_TEXT, "DECLARATION_TEXT", false));
            properties.addElement(new PropInfo(RwiProperty.DEFINITION_END_POSITION, "DEFINITION_END_POSITION", false));
            properties.addElement(new PropInfo(RwiProperty.DEFINITION_FILE, "DEFINITION_FILE", false));
            properties.addElement(new PropInfo(RwiProperty.DEFINITION_START_POSITION, "DEFINITION_START_POSITION", false));
            properties.addElement(new PropInfo(RwiProperty.DESTRUCTOR, "DESTRUCTOR"));
            properties.addElement(new PropInfo(RwiProperty.DIRECTORIES, "DIRECTORIES", false, true));
            properties.addElement(new PropInfo(RwiProperty.DIRECTORY_PACKAGE, "DIRECTORY_PACKAGE"));
            properties.addElement(new PropInfo(RwiProperty.DOC, "DOC", false));
            properties.addElement(new PropInfo(RwiProperty.END_POSITION, "END_POSITION", false));
            properties.addElement(new PropInfo(RwiProperty.EXTENDS, "EXTENDS", false, true));
            properties.addElement(new PropInfo(RwiProperty.FILE, "FILE", false));
            properties.addElement(new PropInfo(RwiProperty.FILES, "FILES", false, true));
            properties.addElement(new PropInfo(RwiProperty.FINAL, "FINAL"));
            properties.addElement(new PropInfo(RwiProperty.FULL_NAME, "FULL_NAME", false));
            properties.addElement(new PropInfo(RwiProperty.HYPERLINK, "HYPERLINK", false, true));
            properties.addElement(new PropInfo(RwiProperty.IMPLEMENTS, "IMPLEMENTS", false, true));
            properties.addElement(new PropInfo(RwiProperty.IMPORT, "IMPORT"));
            properties.addElement(new PropInfo(RwiProperty.INITIAL_VALUE, "INITIAL_VALUE", false));
            properties.addElement(new PropInfo(RwiProperty.INLINE, "INLINE"));
            properties.addElement(new PropInfo(RwiProperty.INTERFACE, "INTERFACE"));
            properties.addElement(new PropInfo(RwiProperty.LANGUAGE, "LANGUAGE", false));
            properties.addElement(new PropInfo(RwiProperty.LINK_MEMBER, "LINK_MEMBER", false));
            properties.addElement(new PropInfo(RwiProperty.LINK_MEMBER, "LINK_MEMBER", false));
            properties.addElement(new PropInfo(RwiProperty.LINK_PREFIX, "LINK_PREFIX"));
            properties.addElement(new PropInfo(RwiProperty.MEMBER_LINK, "MEMBER_LINK", false));
            properties.addElement(new PropInfo(RwiProperty.MEMBER_SIGNATURE, "MEMBER_SIGNATURE", false));
            properties.addElement(new PropInfo(RwiProperty.MODEL, "MODEL"));
            properties.addElement(new PropInfo(RwiProperty.NAME, "NAME", false));
            properties.addElement(new PropInfo(RwiProperty.NATIVE, "NATIVE"));
            properties.addElement(new PropInfo(RwiProperty.PACKAGE_LOCAL, "PACKAGE_LOCAL"));
            properties.addElement(new PropInfo(RwiProperty.PARAMETER, "PARAMETER", false, true));
            properties.addElement(new PropInfo(RwiProperty.PARAMETERS_TEXT, "PARAMETERS_TEXT", false));
            properties.addElement(new PropInfo(RwiProperty.PHYSICAL_PACKAGE, "PHYSICAL_PACKAGE"));
            properties.addElement(new PropInfo(RwiProperty.PRIVATE, "PRIVATE"));
            properties.addElement(new PropInfo(RwiProperty.PUBLIC, "PUBLIC"));
            properties.addElement(new PropInfo(RwiProperty.PROTECTED, "PROTECTED"));
            properties.addElement(new PropInfo(RwiProperty.PURE, "PURE"));
            properties.addElement(new PropInfo(RwiProperty.READ_ONLY, "READ_ONLY"));
            properties.addElement(new PropInfo(RwiProperty.REFERENCED_ELEMENT, "REFERENCED_ELEMENT", false));
            properties.addElement(new PropInfo(RwiProperty.RETURN_TYPE, "RETURN_TYPE", false));
            properties.addElement(new PropInfo(RwiProperty.RETURN_TYPE_REFERENCED_ELEMENT,
                "RETURN_TYPE_REFERENCED_ELEMENT", false));
            properties.addElement(new PropInfo(RwiProperty.SHAPE_TYPE, "SHAPE_TYPE", false));
            properties.addElement(new PropInfo(RwiProperty.START_POSITION, "START_POSITION", false));
            properties.addElement(new PropInfo(RwiProperty.STATIC, "STATIC"));
            properties.addElement(new PropInfo(RwiProperty.SYNCHRONIZED, "SYNCHRONIZED"));
            properties.addElement(new PropInfo(RwiProperty.TEXT, "TEXT", false));
            properties.addElement(new PropInfo(RwiProperty.THROW, "THROW", false, true));
            properties.addElement(new PropInfo(RwiProperty.TRANSIENT, "TRANSIENT"));
            properties.addElement(new PropInfo(RwiProperty.TYPE, "TYPE", false));
            properties.addElement(new PropInfo(RwiProperty.TYPE_REFERENCED_ELEMENT, "TYPE_REFERENCED_ELEMENT", false));
            properties.addElement(new PropInfo(RwiProperty.UML_PARAMETERS_TEXT, "UML_PARAMETERS_TEXT", false));
            properties.addElement(new PropInfo(RwiProperty.UNIQUE_NAME, "UNIQUE_NAME", false));
            properties.addElement(new PropInfo(RwiProperty.VIEW_TYPE, "VIEW_TYPE", false));
            properties.addElement(new PropInfo(RwiProperty.VOLATILE, "VOLATILE"));
        }

        /**
         * Since this class extends RwiVisitorAdapter and doesn't overwrite any
         * of its method, this method will be called for every RwiElement.
         *
         * @param element RwiElement object
         * @return a DefaultMutableTreeNode with all the properties the element
         * has (non-null and active boolean properties)
         */
        public Object visitElement(RwiElement element)
        {
            DefaultMutableTreeNode root =
                new DefaultMutableTreeNode("RwiProperties for \"" +
                element.getProperty(RwiProperty.NAME) +
                "\"(properties whose values are 'null' of 'false' are not shown)");
            analyzePropertyMap(root, element);
            return root;
        }

        /**
         * Populates the given node with the properties the
         * specified RwiPropertyMap has.
         *
         * @param node DefaultMutableTreeNode object
         * @param propertyMap RwiPropertyMap object
         */
        private void analyzePropertyMap(DefaultMutableTreeNode node, RwiPropertyMap propertyMap)
        {
            // properties size
            final int propertiesSize = properties.size();

            // process each property
            for (int i = 0; i < propertiesSize; i++)
            {
                // getting property info
                PropInfo nextPropInfo = (PropInfo)properties.elementAt(i);

                if ((nextPropInfo.isBoolean() && propertyMap.hasProperty(nextPropInfo.getPropertyName())) ||
                    nextPropInfo.isMultiple() || propertyMap.getProperty(nextPropInfo.getPropertyName()) != null)
                {
                        DefaultMutableTreeNode newNode = null;

                        //used to avoid adding an empty node for multiple string properties
                        boolean addNewNode = true;

                        // if rpoerty is boolean
                        if (nextPropInfo.isBoolean())
                        {
                            newNode =
                                new DefaultMutableTreeNode(nextPropInfo.getVisibleName() +
                                "(boolean) = true");
                        }
                        // if property is miltiple string one
                        else if (nextPropInfo.isMultiple())
                        {
                            newNode =
                                new DefaultMutableTreeNode(nextPropInfo.getVisibleName() +
                                "(multiple string property)");

                            // getting enumeration of all property string
                            RwiPropertyEnumeration rwiProperties =
                                propertyMap.properties(nextPropInfo.getPropertyName());

                            // process each property string
                            while (rwiProperties.hasMoreElements())
                            {
                                analyzeOneRwiProperty
                                    (newNode, nextPropInfo.getVisibleName(),
                                    rwiProperties.nextRwiProperty());
                            }

                            if (newNode.getChildCount() == 0)
                            {
                                addNewNode = false;
                            }
                        }
                        else // property is single string one
                        {
                            newNode =
                                new DefaultMutableTreeNode(nextPropInfo.getVisibleName() +
                                " = \"" +
                                propertyMap.getProperty(nextPropInfo.getPropertyName()) +
                                "\"");
                        }
                        if (addNewNode)
                        {
                            node.add(newNode);
                        }
                }
            }
        }

        /**
         * Populates the given node with the node(s) storing the values of
         * the specified RwiProperty.
         * If it does not have subproperties (see RwiProperty interface description)
         * the method will create only one node. If it has, it will populate
         * this subnode with nodes for that subproperties.
         *
         * @param node DefaultMutableTreeNode object
         * @param visibleName visible name string
         * @param rwiProperty RwiProperty object
         */
        private void analyzeOneRwiProperty
            (DefaultMutableTreeNode node, String visibleName, RwiProperty rwiProperty)
        {
            DefaultMutableTreeNode newNode = null;

            // if there are subproperties
            if (rwiProperty.getSubproperties() != null)
            {
                newNode = new DefaultMutableTreeNode(visibleName +
                    " = \"" + rwiProperty.getValue() + "\". Subproperties:");
                analyzePropertyMap(newNode, rwiProperty.getSubproperties());
            }
            // there are not subproperties
            else
            {
                newNode = new DefaultMutableTreeNode(visibleName +
                    " = " + rwiProperty.getValue());
            }
            node.add(newNode);
        }

        // properties vector
        private Vector properties;

        /**
        * Utility class. It is used to contain information about RwiProperty.
        */
        private class PropInfo
        {
            /**
            * Creates class instance with specified parameters.
            *
            * @param propertyName constant from the RwiProperty interface
            * @param visibleName what to display as a name of this property
            * @param isBoolean true, if property is boolean, false if it's string
            * @param isMultiple true, if multiple string propertyis, false, if it's single string one
            */
            public PropInfo
                (String propertyName, String visibleName, boolean isBooleanFlag, boolean isMultipleFlag)
            {
                myPropertyName = propertyName;
                myVisibleName = visibleName;
                myIsBoolean = isBooleanFlag;
                myIsMultiple = isMultipleFlag;
            }

            /**
            * Creates class instance with specified parameters.
            * Created property is boolean by default.
            *
            * @param propertyName constant from the RwiProperty interface
            * @param visibleName what to display as a name of this property
            */
            public PropInfo(String propertyName, String visibleName)
            {
                this(propertyName, visibleName, true, false);
            }

            /**
            * Creates class instance with specified parameters.
            * If specified property is string one, it will be single line,
            * by default.
            *
            * @param propertyName constant from the RwiProperty interface
            * @param visibleName what to display as a name of this property
            * @param isBoolean true, if property is boolean, false if it's string
            */
            public PropInfo(String propertyName, String visibleName, boolean isBoolean)
            {
                this(propertyName, visibleName, isBoolean, false);
            }

            /**
            * Gets property name.
            *
            * @return string property name
            */
            public String getPropertyName() { return myPropertyName; }

            /**
            * Gets visible property name.
            *
            * @return string visible property name
            */
            public String getVisibleName() { return myVisibleName; }

            /**
            * Gets info if property is boolean, or string.
            *
            * @return true, if property is boolean, false, if it's string one
            */
            public boolean isBoolean() { return myIsBoolean; }

            /**
            * Gets info if property is multiple, or not.
            *
            * @return true, if property is multiple string; false, if it's single string one
            */
            public boolean isMultiple() { return myIsMultiple; }

            private String myPropertyName;  // property name
            private String myVisibleName;   // visible property name
            private boolean myIsBoolean;    // boolean flag
            private boolean myIsMultiple;   // multiple flag
        }
    }
}




