Ignore:
Timestamp:
09/18/12 16:46:41 (12 years ago)
Author:
sherbold
Message:
  • modified GUIModel to not automatically merge nodes during the creation of the model, but rather after the creation is completed through a call of condenseModel
  • added command condenseGuiModel
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/guimodel/GUIModel.java

    r747 r820  
     1 
    12package de.ugoe.cs.quest.eventcore.guimodel; 
    23 
     
    78import java.util.LinkedList; 
    89import java.util.List; 
    9 import java.util.logging.Level; 
    10  
    11 import de.ugoe.cs.util.console.Console; 
    1210 
    1311/** 
     
    1614 * platform independent. It may have several root nodes, as some GUIs are made up of several Frames 
    1715 * being independent from each other. The GUI model is filled using the 
    18  * {@link #integratePath(List, IGUIElementFactory)} method.   
     16 * {@link #integratePath(List, IGUIElementFactory)} method. 
    1917 * </p> 
    2018 *  
     19 * TODO: getChildren and getParent should be rewritten to at least throw warnings, in case there are 
     20 * multiple nodes in allNodes that match the current GUI element. 
     21 *  
    2122 * @version $Revision: $ $Date: 14.08.2012$ 
    22  * @author 2012, last modified by $Author: pharms$ 
     23 * @author Patrick Harms, Steffen Herbold 
    2324 */ 
    2425public class GUIModel { 
    25      
     26 
    2627    /** 
    2728     * <p> 
     
    3031     */ 
    3132    private TreeNode root = new TreeNode(); 
    32      
     33 
    3334    /** 
    3435     * <p> 
     
    4445     * a leaf node. Such a path can be added to the tree. The method checks, if any of the GUI 
    4546     * elements denoted by the path already exists. If so, it reuses it. It may therefore also 
    46      * return an existing GUI element being the leaf node of the provided path. If a GUI element 
    47      * of the path does not exist yet, it creates a new one using the provided GUI element factory. 
    48      * </p> 
    49      * <p> 
    50      * If a GUI element specification describes an existing GUI element or not is determined 
    51      * through comparing the GUI element specifications of the existing GUI elements with the 
    52      * ones provided in the path. The comparison is done using the 
    53      * {@link IGUIElementSpec#getSimilarity(IGUIElementSpec)} method. The comparison is only done 
    54      * on the correct levels. I.e. the currently known root elements of the tree are only compared 
    55      * to the first element in the path. If the correct one is found or created, its children are 
     47     * return an existing GUI element being the leaf node of the provided path. If a GUI element of 
     48     * the path does not exist yet, it creates a new one using the provided GUI element factory. 
     49     * </p> 
     50     * <p> 
     51     * If a GUI element specification describes an existing GUI element or not is determined through 
     52     * comparing the GUI element specifications of the existing GUI elements with the ones provided 
     53     * in the path. The comparison is done using the 
     54     * {@link IGUIElementSpec#getSimilarity(IGUIElementSpec)} method. The comparison is only done on 
     55     * the correct levels. I.e. the currently known root elements of the tree are only compared to 
     56     * the first element in the path. If the correct one is found or created, its children are 
    5657     * compared only to the second specification in the path, and so on. 
    5758     * </p> 
    5859     * <p> 
    5960     * The returned GUI elements are singletons. I.e. it is tried to return always the identical 
    60      * object for the same denoted element. However, while creating the GUI model, the similarity 
    61      * of GUI elements may change. Therefore, the method might determine, that two formerly 
    62      * different nodes are now similar. (This may happen, e.g. if GUI elements do not have initial 
    63      * names which are set afterwards. Therefore, first they are handled differently and later 
    64      * they can be identified as being the same.) In such a case, there are already several GUI 
    65      * element objects instantiated for the same GUI element. The singleton paradigm gets broken. 
    66      * Therefore, such GUI element objects are registered with each other, so that their equal 
    67      * method can determine equality again correctly, although the objects are no singletons 
    68      * anymore. 
    69      * </p> 
    70      * 
    71      * @param guiElementPath    the path to integrate into the model 
    72      * @param guiElementFactory the GUI element factory to be used for instantiating GUI element 
    73      *                          objects 
    74      *                           
     61     * object for the same denoted element. However, while creating the GUI model, the similarity of 
     62     * GUI elements may change. Therefore, the method might determine, that two formerly different 
     63     * nodes are now similar. (This may happen, e.g. if GUI elements do not have initial names which 
     64     * are set afterwards. Therefore, first they are handled differently and later they can be 
     65     * identified as being the same.) In such a case, there are already several GUI element objects 
     66     * instantiated for the same GUI element. The singleton paradigm gets broken. Therefore, such 
     67     * GUI element objects are registered with each other, so that their equal method can determine 
     68     * equality again correctly, although the objects are no singletons anymore. 
     69     * </p> 
     70     *  
     71     * @param guiElementPath 
     72     *            the path to integrate into the model 
     73     * @param guiElementFactory 
     74     *            the GUI element factory to be used for instantiating GUI element objects 
     75     *  
    7576     * @return The GUI element object representing the GUI element denoted by the provided path 
    7677     *  
    77      * @throws GUIModelException thrown in cases such as the GUI element object could not be 
    78      *                           instantiated 
    79      * @throws IllegalArgumentException if the provided path is invalid. 
     78     * @throws GUIModelException 
     79     *             thrown in cases such as the GUI element object could not be instantiated 
     80     * @throws IllegalArgumentException 
     81     *             if the provided path is invalid. 
    8082     */ 
    8183    public IGUIElement integratePath(List<? extends IGUIElementSpec> guiElementPath, 
    82                                      IGUIElementFactory              guiElementFactory) 
     84                                     IGUIElementFactory guiElementFactory) 
    8385        throws GUIModelException, IllegalArgumentException 
    8486    { 
    8587        if ((guiElementPath == null) || (guiElementPath.size() <= 0)) { 
    86             throw new IllegalArgumentException 
    87                 ("GUI element path must contain at least one element"); 
    88         } 
    89          
     88            throw new IllegalArgumentException("GUI element path must contain at least one element"); 
     89        } 
     90 
    9091        List<IGUIElementSpec> remainingPath = new LinkedList<IGUIElementSpec>(); 
    91          
    92         for (IGUIElementSpec spec : guiElementPath) 
    93         { 
     92 
     93        for (IGUIElementSpec spec : guiElementPath) { 
    9494            remainingPath.add(spec); 
    9595        } 
    96          
     96 
    9797        return integratePath(root, remainingPath, guiElementFactory); 
    9898    } 
     
    100100    /** 
    101101     * <p> 
    102      * Returns all children of the provided GUI element or null, if it does not have any or the 
    103      * node is unknown. 
    104      * </p> 
    105      * 
    106      * @param guiElement the GUI element of which the children shall be returned 
     102     * Returns all children of the provided GUI element or null, if it does not have any or the node 
     103     * is unknown. 
     104     * </p> 
     105     *  
     106     * @param guiElement 
     107     *            the GUI element of which the children shall be returned 
    107108     *  
    108109     * @return As described 
     
    112113            if (node.guiElement.equals(guiElement)) { 
    113114                List<IGUIElement> result = new ArrayList<IGUIElement>(); 
    114                  
     115 
    115116                if (node.children != null) { 
    116117                    for (TreeNode child : node.children) { 
    117                       result.add(child.guiElement); 
     118                        result.add(child.guiElement); 
    118119                    } 
    119120                } 
    120                  
     121 
    121122                return result; 
    122123            } 
    123124        } 
    124          
     125 
    125126        return null; 
    126127    } 
     
    131132     * parent (i.e. if it is a root node) or if the node is unknown. 
    132133     * </p> 
    133      * 
    134      * @param guiElement the GUI element of which the parent shall be returned 
     134     *  
     135     * @param guiElement 
     136     *            the GUI element of which the parent shall be returned 
    135137     *  
    136138     * @return As described 
     
    144146            } 
    145147        } 
    146          
     148 
    147149        return null; 
    148150    } 
     
    152154     * Returns all root GUI elements of the model or an empty list, if the model is empty 
    153155     * </p> 
    154      * 
     156     *  
    155157     * @return As described 
    156158     */ 
    157159    public List<IGUIElement> getRootElements() { 
    158160        List<IGUIElement> roots = new ArrayList<IGUIElement>(); 
    159          
     161 
    160162        if (root.children != null) { 
    161163            for (TreeNode rootChild : root.children) { 
     
    163165            } 
    164166        } 
    165          
     167 
    166168        return roots; 
    167169    } 
     
    173175     * </p> 
    174176     *  
    175      * @param out      The stream to dump the textual representation of the model to 
    176      * @param encoding The encoding to be used while dumping 
     177     * @param out 
     178     *            The stream to dump the textual representation of the model to 
     179     * @param encoding 
     180     *            The encoding to be used while dumping 
    177181     */ 
    178182    public void dump(OutputStream out, String encoding) { 
    179183        PrintStream stream; 
    180          
     184 
    181185        if (out instanceof PrintStream) { 
    182186            stream = (PrintStream) out; 
     
    191195            } 
    192196        } 
    193          
     197 
    194198        for (IGUIElement root : getRootElements()) { 
    195199            dumpGUIElement(stream, root, ""); 
     
    199203    /** 
    200204     * <p> 
    201      * internally integrates a path as the children of the provided parent node. This method 
    202      * is recursive and calls itself, for the child of the parent node, that matches the first 
    203      * element in the remaining path. 
    204      * </p> 
    205      * 
    206      * @param parentNode        the parent node to add children for  
    207      * @param guiElementPath    the path of children to be created starting with the parent node 
    208      * @param guiElementFactory the GUI element factory to be used for instantiating GUI element 
    209      *                          objects 
    210      *                           
     205     * TODO: comment 
     206     * </p> 
     207     *  
     208     */ 
     209    public void condenseModel() { 
     210        mergeSimilarChildren(root); 
     211    } 
     212 
     213    /** 
     214     * <p> 
     215     * internally integrates a path as the children of the provided parent node. This method is 
     216     * recursive and calls itself, for the child of the parent node, that matches the first element 
     217     * in the remaining path. 
     218     * </p> 
     219     *  
     220     * @param parentNode 
     221     *            the parent node to add children for 
     222     * @param guiElementPath 
     223     *            the path of children to be created starting with the parent node 
     224     * @param guiElementFactory 
     225     *            the GUI element factory to be used for instantiating GUI element objects 
     226     *  
    211227     * @return The GUI element object representing the GUI element denoted by the provided path 
    212228     *  
    213      * @throws GUIModelException thrown in cases such as the GUI element object could not be 
    214      *                           instantiated 
    215      */ 
    216     private IGUIElement integratePath(TreeNode                        parentNode, 
     229     * @throws GUIModelException 
     230     *             thrown in cases such as the GUI element object could not be instantiated 
     231     */ 
     232    private IGUIElement integratePath(TreeNode parentNode, 
    217233                                      List<? extends IGUIElementSpec> remainingPath, 
    218                                       IGUIElementFactory              guiElementFactory) 
     234                                      IGUIElementFactory guiElementFactory) 
    219235        throws GUIModelException 
    220236    { 
    221237        IGUIElementSpec specToIntegrateElementFor = remainingPath.remove(0); 
    222238 
    223         List<TreeNode> similarNodes = 
    224             determineSimilarChildNodes(parentNode, specToIntegrateElementFor); 
    225          
    226         if (similarNodes.size() > 1) { 
    227             // this may happen, if the GUI elements changed over time (e.g. their name is usually 
    228             // set later in the program execution) and if they now match because of the changes. 
    229             // So perform a merge of all similar children of the current parent node to reduce the 
    230             // model and then try the determination of matching children again. 
    231             mergeSimilarChildren(parentNode); 
    232             similarNodes = determineSimilarChildNodes(parentNode, specToIntegrateElementFor); 
    233              
    234             if (similarNodes.size() > 1) { 
    235                 // this can happen, because the similarity check is not transitive. The new GUI 
    236                 // element may be similar to two or more existing ones, but the existing ones 
    237                 // may not be similar to each other. As an example, the new GUI element may 
    238                 // not yet provide sufficient information (such as all names it will have during 
    239                 // the execution of the program). Therefore the similarity check with GUI elements 
    240                 // that already contain more information may return true. But the similarity check 
    241                 // of two GUI elements that already carry a lot of information may return false, 
    242                 // although both are similar to the new GUI element. Therefore, we try a selection 
    243                 // based on the children of the existing and new GUI elements. The one for which 
    244                 // the existing children match best is selected to be the right one. 
    245                 similarNodes = considerSubChildren(similarNodes, remainingPath); 
    246  
    247                 if (similarNodes.size() > 1) { 
    248                     Console.traceln(Level.WARNING, "TODO: implement handling to many similar" + 
    249                                     "children: " + specToIntegrateElementFor); 
    250                     for (TreeNode similarNode : similarNodes) { 
    251                         Console.traceln(Level.WARNING, "    " + similarNode.guiElement); 
    252                     } 
    253                     Console.traceln(Level.WARNING, ""); 
    254                 } 
    255             } 
    256         } 
    257         else if (similarNodes.size() == 1) { 
    258             similarNodes.get(0).guiElement.updateSpecification(specToIntegrateElementFor); 
    259         } 
    260         else if (similarNodes.size() == 0) { 
    261             // if we get here, the corresponding path does not exist yet. So create it 
    262             IGUIElement newElement = guiElementFactory.instantiateGUIElement 
    263                 (specToIntegrateElementFor, parentNode.guiElement); 
    264              
    265             similarNodes.add(parentNode.addChild(newElement)); 
    266         } 
    267          
     239        TreeNode child = findEqualChild(parentNode, specToIntegrateElementFor); 
     240        if (child != null) { 
     241            // TODO this call should be deprecated and change nothing 
     242            child.guiElement.updateSpecification(specToIntegrateElementFor); 
     243        } 
     244        else { 
     245            IGUIElement newElement = 
     246                guiElementFactory.instantiateGUIElement(specToIntegrateElementFor, 
     247                                                        parentNode.guiElement); 
     248 
     249            child = parentNode.addChild(newElement); 
     250        } 
     251 
    268252        if (remainingPath.size() > 0) { 
    269             return integratePath(similarNodes.get(0), remainingPath, guiElementFactory); 
     253            return integratePath(child, remainingPath, guiElementFactory); 
    270254        } 
    271255        else { 
    272             return similarNodes.get(0).guiElement; 
    273         } 
    274     } 
    275  
    276     /** 
    277      * <p> 
    278      * Determines all children of the provided node, which are similar to the provided 
    279      * specification. 
    280      * </p> 
    281      */ 
    282     private List<TreeNode> determineSimilarChildNodes(TreeNode        parentNode, 
    283                                                       IGUIElementSpec specToMatch) 
    284     { 
    285         List<TreeNode> similarChildren = new ArrayList<TreeNode>(); 
    286          
     256            return child.guiElement; 
     257        } 
     258    } 
     259 
     260    /** 
     261     * <p> 
     262     * TODO: comment 
     263     * </p> 
     264     *  
     265     * @param parentNode 
     266     * @param specToMatch 
     267     * @return 
     268     */ 
     269    private TreeNode findEqualChild(TreeNode parentNode, IGUIElementSpec specToMatch) { 
    287270        if (parentNode.children != null) { 
    288271            for (TreeNode child : parentNode.children) { 
    289                 if (specToMatch.getSimilarity(child.guiElement.getSpecification())) { 
    290                     similarChildren.add(child); 
     272                if (specToMatch.equals(child.guiElement.getSpecification())) { 
     273                    return child; 
    291274                } 
    292275            } 
    293276        } 
    294          
    295         return similarChildren; 
    296     } 
    297  
    298     /** 
    299      * <p> 
    300      * This method is called in the case, that several child nodes of a parent node are similar 
    301      * to a node to be integrated into the model. This method tries to determine the similar child 
    302      * nodes of which the sub children match best to the further path to be integrated. This method 
    303      * does nothing, if the similar children do not have children yet of if the remaining path 
    304      * does not denote further children.  
    305      * </p> 
    306      * 
    307      * @return a hopefully reduced list of similar nodes based on their children. 
    308      */ 
    309     private List<TreeNode> considerSubChildren(List<TreeNode>                  similarNodes, 
    310                                                List<? extends IGUIElementSpec> remainingPath) 
    311     { 
    312         List<TreeNode> reducedList = new ArrayList<TreeNode>(); 
    313          
    314         // check, if there are any children to consider and remove any similar node, that has 
    315         // further children 
    316         if (remainingPath.size() <= 0) { 
    317             for (TreeNode similarNode : similarNodes) { 
    318                 if ((similarNode.children == null) || (similarNode.children.size() == 0)) { 
    319                     reducedList.add(similarNode); 
    320                 } 
    321             } 
    322         } 
    323         else { 
    324             // if there are further children to consider, then check if there is already a child 
    325             // node that has an appropriate child 
    326             IGUIElementSpec subChildSpec = remainingPath.get(0); 
    327             for (TreeNode similarNode : similarNodes) { 
    328                 if (similarNode.children != null) { 
    329                     for (TreeNode subchild : similarNode.children) { 
    330                         if (subchild.guiElement.getSpecification().getSimilarity(subChildSpec)) { 
    331                             reducedList.add(similarNode); 
    332                             break; 
    333                         } 
     277        return null; 
     278    } 
     279 
     280    /** 
     281     * <p> 
     282     * merges similar children of a parent node. The method compares all children of the parent node 
     283     * with each other. If two of them are similar, it merges them, registers them with each other 
     284     * for equality checks, and removes one of them from the list of children. 
     285     * </p> 
     286     */ 
     287    private void mergeSimilarChildren(TreeNode parentNode) { 
     288        if (parentNode.children == null || parentNode.children.isEmpty()) { 
     289            return; 
     290        } 
     291 
     292        // lets first merge the grandchildren 
     293        for (TreeNode child : parentNode.children) { 
     294            mergeSimilarChildren(child); 
     295        } 
     296 
     297        boolean performedMerge; 
     298 
     299        do { 
     300            performedMerge = false; 
     301            for (int i = 0; !performedMerge && i < parentNode.children.size(); i++) { 
     302                IGUIElementSpec elemSpec1 = 
     303                    parentNode.children.get(i).guiElement.getSpecification(); 
     304                for (int j = i + 1; !performedMerge && j < parentNode.children.size(); j++) { 
     305                    IGUIElementSpec elemSpec2 = 
     306                        parentNode.children.get(j).guiElement.getSpecification(); 
     307                    if (elemSpec1.getSimilarity(elemSpec2)) { 
     308                        TreeNode replacement = 
     309                            mergeTreeNodes(parentNode.children.get(i), parentNode.children.get(j)); 
     310 
     311                        parentNode.children.set(i, replacement); 
     312                        parentNode.children.remove(j); 
     313                        performedMerge = true; 
     314                        i--; 
     315                        break; 
    334316                    } 
    335317                } 
    336318            } 
    337319        } 
    338          
    339         return reducedList; 
    340     } 
    341  
    342     /** 
    343      * <p> 
    344      * merges similar children of a parent node. The method compares all children of the parent 
    345      * node with each other. If two of them are similar, it merges them, registers them with each 
    346      * other for equality checks, and removes one of them from the list of children.  
    347      * </p> 
    348      */ 
    349     private void mergeSimilarChildren(TreeNode parentNode) { 
    350         boolean performedMerge; 
    351          
    352         do { 
    353             performedMerge = false; 
    354             if (parentNode.children != null) { 
    355                 for (int i = 0; (!performedMerge) && (i < parentNode.children.size()); i++) { 
    356                     for (int j = i + 1; j < parentNode.children.size(); j++) { 
    357                         IGUIElement elem1 = parentNode.children.get(i).guiElement; 
    358                         IGUIElement elem2 = parentNode.children.get(j).guiElement; 
    359                         if (elem1.getSpecification().getSimilarity(elem2.getSpecification())) { 
    360                             TreeNode replacement = mergeTreeNodes(parentNode.children.get(i), 
    361                                                                   parentNode.children.get(j)); 
    362                              
    363                             parentNode.children.set(i, replacement); 
    364                             parentNode.children.remove(j); 
    365                             performedMerge = true; 
    366                             break; 
    367                         } 
    368                     } 
    369                 } 
    370             } 
    371         } 
    372320        while (performedMerge); 
    373321    } 
     
    375323    /** 
    376324     * <p> 
    377      * merges two nodes with each other. Merging means registering the GUI element objects with 
    378      * each other for equality checks. Further it add all children of both nodes to a new 
    379      * replacing node. Afterwards, all similar nodes of the replacement node are merged as well. 
    380      * </p> 
    381      * 
     325     * merges two nodes with each other. Merging means registering the GUI element objects with each 
     326     * other for equality checks. Further it add all children of both nodes to a new replacing node. 
     327     * Afterwards, all similar nodes of the replacement node are merged as well. 
     328     * </p> 
     329     *  
    382330     * @return a tree node being the merge of the two provided nodes. 
    383331     */ 
    384332    private TreeNode mergeTreeNodes(TreeNode treeNode1, TreeNode treeNode2) { 
    385         TreeNode replacement = new TreeNode(); 
    386          
    387         replacement.guiElement = treeNode1.guiElement; 
    388          
    389333        // the following two lines are needed to preserve the references to the existing GUI 
    390334        // elements. If two elements are the same, one should be deleted to make the elements 
     
    392336        // these, we simply register the equal GUI elements with each other so that an equals 
    393337        // check can return true. 
    394         replacement.guiElement.addEqualGUIElement(treeNode2.guiElement); 
    395         treeNode2.guiElement.addEqualGUIElement(replacement.guiElement); 
    396          
     338        treeNode1.guiElement.addEqualGUIElement(treeNode2.guiElement); 
     339        treeNode2.guiElement.addEqualGUIElement(treeNode1.guiElement); 
     340 
     341        // and now a replacement node that is the merge of treeNode1 and treeNode2 is created 
     342        TreeNode replacement = new TreeNode(); 
     343        replacement.guiElement = treeNode1.guiElement; 
    397344        if (treeNode1.children != null) { 
    398345            for (TreeNode child : treeNode1.children) { 
    399                 replacement.addChild(child.guiElement); 
    400             } 
    401         } 
    402          
     346                // replacement.addChild(child.guiElement); 
     347                replacement.addChildNode(child); 
     348            } 
     349        } 
    403350        if (treeNode2.children != null) { 
    404351            for (TreeNode child : treeNode2.children) { 
    405                 replacement.addChild(child.guiElement); 
    406             } 
    407         } 
    408          
     352                // replacement.addChild(child.guiElement); 
     353                replacement.addChildNode(child); 
     354            } 
     355        } 
     356 
    409357        mergeSimilarChildren(replacement); 
    410          
     358 
    411359        replacement.guiElement.updateSpecification(treeNode2.guiElement.getSpecification()); 
    412          
     360 
     361        // finally, update the known nodes list 
     362        // if you don't do this getChildren will return wrong things and very bad things happen! 
     363        allNodes.remove(treeNode1); 
     364        allNodes.remove(treeNode2); 
     365        allNodes.add(replacement); 
     366 
    413367        return replacement; 
    414368    } 
     
    416370    /** 
    417371     * <p> 
    418      * dumps a GUI element to the stream. A dump contains the toString() representation of the 
    419      * GUI element as well as a indented list of its children surrounded by braces. 
     372     * dumps a GUI element to the stream. A dump contains the toString() representation of the GUI 
     373     * element as well as a indented list of its children surrounded by braces. 
    420374     * </p> 
    421375     */ 
     
    445399     * </p> 
    446400     */ 
    447     private class TreeNode 
    448     { 
     401    private class TreeNode { 
    449402        /** */ 
    450403        private IGUIElement guiElement; 
    451          
     404 
    452405        /** */ 
    453406        private List<TreeNode> children; 
    454          
     407 
    455408        /** */ 
    456         //private TreeNode parent; 
    457          
     409        // private TreeNode parent; 
     410 
    458411        /** 
    459412         * <p> 
     
    461414         * </p> 
    462415         */ 
    463         private TreeNode addChild(IGUIElement guiElement) 
    464         { 
    465             if (children == null) 
    466             { 
     416        private TreeNode addChild(IGUIElement guiElement) { 
     417            if (children == null) { 
    467418                children = new ArrayList<TreeNode>(); 
    468419            } 
    469              
     420 
    470421            TreeNode child = new TreeNode(); 
    471422            child.guiElement = guiElement; 
    472             //child.parent = this; 
     423            // child.parent = this; 
    473424            children.add(child); 
    474              
     425 
    475426            allNodes.add(child); 
    476              
     427 
    477428            return child; 
    478429        } 
    479430 
    480         /* (non-Javadoc) 
     431        /** 
     432         *  
     433         * <p> 
     434         * TODO: comment 
     435         * </p> 
     436         *  
     437         * @param node 
     438         * @return 
     439         */ 
     440        private TreeNode addChildNode(TreeNode node) { 
     441            if (children == null) { 
     442                children = new ArrayList<TreeNode>(); 
     443            } 
     444            children.add(node); 
     445            return node; 
     446        } 
     447 
     448        /* 
     449         * (non-Javadoc) 
     450         *  
    481451         * @see java.lang.Object#toString() 
    482452         */ 
Note: See TracChangeset for help on using the changeset viewer.