1 /* DefaultMutableTreeNode.java --
2    Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing.tree;
40 
41 import gnu.java.util.EmptyEnumeration;
42 
43 import java.io.IOException;
44 import java.io.ObjectInputStream;
45 import java.io.ObjectOutputStream;
46 import java.io.Serializable;
47 import java.util.ArrayList;
48 import java.util.Enumeration;
49 import java.util.LinkedList;
50 import java.util.NoSuchElementException;
51 import java.util.Stack;
52 import java.util.Vector;
53 
54 
55 /**
56  * A default implementation of the {@link MutableTreeNode} interface.
57  *
58  * @author Andrew Selkirk
59  * @author Robert Schuster (robertschuster@fsfe.org)
60  */
61 public class DefaultMutableTreeNode
62   implements Cloneable, MutableTreeNode, Serializable
63 {
64   private static final long serialVersionUID = -4298474751201349152L;
65 
66   /**
67    * An empty enumeration, returned by {@link #children()} if a node has no
68    * children.
69    */
70   public static final Enumeration<TreeNode> EMPTY_ENUMERATION =
71     new EmptyEnumeration<TreeNode>();
72 
73   /**
74    * The parent of this node (possibly <code>null</code>).
75    */
76   protected MutableTreeNode parent;
77 
78   /**
79    * The child nodes for this node (may be empty).
80    */
81   protected Vector<MutableTreeNode> children = new Vector<MutableTreeNode>();
82 
83   /**
84    * userObject
85    */
86   protected transient Object userObject;
87 
88   /**
89    * allowsChildren
90    */
91   protected boolean allowsChildren;
92 
93   /**
94    * Creates a <code>DefaultMutableTreeNode</code> object.
95    * This is equivalent to <code>DefaultMutableTreeNode(null, true)</code>.
96    */
DefaultMutableTreeNode()97   public DefaultMutableTreeNode()
98   {
99     this(null, true);
100   }
101 
102   /**
103    * Creates a <code>DefaultMutableTreeNode</code> object with the given
104    * user object attached to it. This is equivalent to
105    * <code>DefaultMutableTreeNode(userObject, true)</code>.
106    *
107    * @param userObject the user object (<code>null</code> permitted).
108    */
DefaultMutableTreeNode(Object userObject)109   public DefaultMutableTreeNode(Object userObject)
110   {
111     this(userObject, true);
112   }
113 
114   /**
115    * Creates a <code>DefaultMutableTreeNode</code> object with the given
116    * user object attached to it.
117    *
118    * @param userObject the user object (<code>null</code> permitted).
119    * @param allowsChildren <code>true</code> if the code allows to add child
120    * nodes, <code>false</code> otherwise
121    */
DefaultMutableTreeNode(Object userObject, boolean allowsChildren)122   public DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
123   {
124     this.userObject = userObject;
125     this.allowsChildren = allowsChildren;
126   }
127 
128   /**
129    * Returns a clone of the node.  The clone contains a shallow copy of the
130    * user object, and does not copy the parent node or the child nodes.
131    *
132    * @return A clone of the node.
133    */
clone()134   public Object clone()
135   {
136     return new DefaultMutableTreeNode(this.userObject, this.allowsChildren);
137   }
138 
139   /**
140    * Returns a string representation of the node.  This implementation returns
141    * <code>getUserObject().toString()</code>, or <code>null</code> if there
142    * is no user object.
143    *
144    * @return A string representation of the node (possibly <code>null</code>).
145    */
toString()146   public String toString()
147   {
148     if (userObject == null)
149       return null;
150 
151     return userObject.toString();
152   }
153 
154   /**
155    * Adds a new child node to this node and sets this node as the parent of
156    * the child node.  The child node must not be an ancestor of this node.
157    * If the tree uses the {@link DefaultTreeModel}, you must subsequently
158    * call {@link DefaultTreeModel#reload(TreeNode)}.
159    *
160    * @param child the child node (<code>null</code> not permitted).
161    *
162    * @throws IllegalStateException if {@link #getAllowsChildren()} returns
163    *     <code>false</code>.
164    * @throws IllegalArgumentException if {@link #isNodeAncestor} returns
165    *     <code>true</code>.
166    * @throws IllegalArgumentException if <code>child</code> is
167    *     <code>null</code>.
168    */
add(MutableTreeNode child)169   public void add(MutableTreeNode child)
170   {
171     if (! allowsChildren)
172       throw new IllegalStateException();
173 
174     if (child == null)
175       throw new IllegalArgumentException();
176 
177     if (isNodeAncestor(child))
178       throw new IllegalArgumentException("Cannot add ancestor node.");
179 
180     children.add(child);
181     child.setParent(this);
182   }
183 
184   /**
185    * Returns the parent node of this node.
186    *
187    * @return The parent node (possibly <code>null</code>).
188    */
getParent()189   public TreeNode getParent()
190   {
191     return parent;
192   }
193 
194   /**
195    * Removes the child with the given index from this node.
196    *
197    * @param index the index (in the range <code>0</code> to
198    *     <code>getChildCount() - 1</code>).
199    *
200    * @throws ArrayIndexOutOfBoundsException if <code>index</code> is outside
201    *         the valid range.
202    */
remove(int index)203   public void remove(int index)
204   {
205     MutableTreeNode child = children.remove(index);
206     child.setParent(null);
207   }
208 
209   /**
210    * Removes the given child from this node and sets its parent to
211    * <code>null</code>.
212    *
213    * @param node the child node (<code>null</code> not permitted).
214    *
215    * @throws IllegalArgumentException if <code>node</code> is not a child of
216    *     this node.
217    * @throws IllegalArgumentException if <code>node</code> is null.
218    */
remove(MutableTreeNode node)219   public void remove(MutableTreeNode node)
220   {
221     if (node == null)
222       throw new IllegalArgumentException("Null 'node' argument.");
223     if (node.getParent() != this)
224       throw new IllegalArgumentException(
225           "The given 'node' is not a child of this node.");
226     children.remove(node);
227     node.setParent(null);
228   }
229 
230   /**
231    * writeObject
232    *
233    * @param stream the output stream
234    *
235    * @exception IOException If an error occurs
236    */
writeObject(ObjectOutputStream stream)237   private void writeObject(ObjectOutputStream stream)
238     throws IOException
239   {
240     // TODO: Implement me.
241   }
242 
243   /**
244    * readObject
245    *
246    * @param stream the input stream
247    *
248    * @exception IOException If an error occurs
249    * @exception ClassNotFoundException TODO
250    */
readObject(ObjectInputStream stream)251   private void readObject(ObjectInputStream stream)
252     throws IOException, ClassNotFoundException
253   {
254     // TODO: Implement me.
255   }
256 
257   /**
258    * Inserts given child node at the given index.
259    *
260    * @param node the child node (<code>null</code> not permitted).
261    * @param index the index.
262    *
263    * @throws IllegalArgumentException if <code>node</code> is
264    *     </code>null</code>.
265    */
insert(MutableTreeNode node, int index)266   public void insert(MutableTreeNode node, int index)
267   {
268     if (! allowsChildren)
269       throw new IllegalStateException();
270 
271     if (node == null)
272       throw new IllegalArgumentException("Null 'node' argument.");
273 
274     if (isNodeAncestor(node))
275       throw new IllegalArgumentException("Cannot insert ancestor node.");
276 
277     children.insertElementAt(node, index);
278   }
279 
280   /**
281    * Returns a path to this node from the root.
282    *
283    * @return an array of tree nodes
284    */
getPath()285   public TreeNode[] getPath()
286   {
287     return getPathToRoot(this, 0);
288   }
289 
290   /**
291    * Returns an enumeration containing all children of this node.
292    * <code>EMPTY_ENUMERATION</code> is returned if this node has no children.
293    *
294    * @return an enumeration of tree nodes
295    */
296   @SuppressWarnings("rawtypes") // Required for API compatibility
children()297   public Enumeration children()
298   {
299     if (children.size() == 0)
300       return EMPTY_ENUMERATION;
301 
302     return children.elements();
303   }
304 
305   /**
306    * Set the parent node for this node.
307    *
308    * @param node the parent node
309    */
setParent(MutableTreeNode node)310   public void setParent(MutableTreeNode node)
311   {
312     parent = node;
313   }
314 
315   /**
316    * Returns the child node at a given index.
317    *
318    * @param index the index
319    *
320    * @return the child node
321    */
getChildAt(int index)322   public TreeNode getChildAt(int index)
323   {
324     return children.elementAt(index);
325   }
326 
327   /**
328    * Returns the number of children of this node.
329    *
330    * @return the number of children
331    */
getChildCount()332   public int getChildCount()
333   {
334     return children.size();
335   }
336 
337   /**
338    * Returns the index of the specified child node, or -1 if the node is not
339    * in fact a child of this node.
340    *
341    * @param node  the node (<code>null</code> not permitted).
342    *
343    * @return The index of the specified child node, or -1.
344    *
345    * @throws IllegalArgumentException if <code>node</code> is <code>null</code>.
346    */
getIndex(TreeNode node)347   public int getIndex(TreeNode node)
348   {
349     if (node == null)
350       throw new IllegalArgumentException("Null 'node' argument.");
351     return children.indexOf(node);
352   }
353 
354   /**
355    * Sets the flag that controls whether or not this node allows the addition /
356    * insertion of child nodes.  If the flag is set to <code>false</code>, any
357    * existing children are removed.
358    *
359    * @param allowsChildren  the flag.
360    */
setAllowsChildren(boolean allowsChildren)361   public void setAllowsChildren(boolean allowsChildren)
362   {
363     if (!allowsChildren)
364       removeAllChildren();
365     this.allowsChildren = allowsChildren;
366   }
367 
368   /**
369    * getAllowsChildren
370    *
371    * @return boolean
372    */
getAllowsChildren()373   public boolean getAllowsChildren()
374   {
375     return allowsChildren;
376   }
377 
378   /**
379    * Sets the user object for this node
380    *
381    * @param userObject the user object
382    */
setUserObject(Object userObject)383   public void setUserObject(Object userObject)
384   {
385     this.userObject = userObject;
386   }
387 
388   /**
389    * Returns the user object attached to this node. <code>null</code> is
390    * returned when no user object is set.
391    *
392    * @return the user object
393    */
getUserObject()394   public Object getUserObject()
395   {
396     return userObject;
397   }
398 
399   /**
400    * Removes this node from its parent.
401    */
removeFromParent()402   public void removeFromParent()
403   {
404     parent.remove(this);
405     parent = null;
406   }
407 
408   /**
409    * Removes all child nodes from this node.
410    */
removeAllChildren()411   public void removeAllChildren()
412   {
413     for (int i = getChildCount() - 1; i >= 0; i--)
414       remove(i);
415   }
416 
417   /**
418    * Returns <code>true</code> if <code>node</code> is an ancestor of this
419    * tree node, and <code>false</code> otherwise.  An ancestor node is any of:
420    * <ul>
421    * <li>this tree node;</li>
422    * <li>the parent node (if there is one);</li>
423    * <li>any ancestor of the parent node;</li>
424    * </ul>
425    * If <code>node</code> is <code>null</code>, this method returns
426    * <code>false</code>.
427    *
428    * @param node  the node (<code>null</code> permitted).
429    *
430    * @return A boolean.
431    */
isNodeAncestor(TreeNode node)432   public boolean isNodeAncestor(TreeNode node)
433   {
434     if (node == null)
435       return false;
436 
437     TreeNode current = this;
438 
439     while (current != null && current != node)
440       current = current.getParent();
441 
442     return current == node;
443   }
444 
445   /**
446    * Returns <code>true</code> if <code>node</code> is a descendant of this
447    * tree node, and <code>false</code> otherwise.  A descendant node is any of:
448    * <ul>
449    * <li>this tree node;</li>
450    * <li>the child nodes belonging to this tree node, if there are any;</li>
451    * <li>any descendants of the child nodes;</li>
452    * </ul>
453    * If <code>node</code> is <code>null</code>, this method returns
454    * <code>false</code>.
455    *
456    * @param node  the node (<code>null</code> permitted).
457    *
458    * @return A boolean.
459    */
isNodeDescendant(DefaultMutableTreeNode node)460   public boolean isNodeDescendant(DefaultMutableTreeNode node)
461   {
462     if (node == null)
463       return false;
464 
465     TreeNode current = node;
466 
467     while (current != null
468            && current != this)
469       current = current.getParent();
470 
471     return current == this;
472   }
473 
474   /**
475    * getSharedAncestor
476    *
477    * @param node TODO
478    *
479    * @return TreeNode
480    */
getSharedAncestor(DefaultMutableTreeNode node)481   public TreeNode getSharedAncestor(DefaultMutableTreeNode node)
482   {
483     TreeNode current = this;
484     ArrayList<TreeNode> list = new ArrayList<TreeNode>();
485 
486     while (current != null)
487       {
488         list.add(current);
489         current = current.getParent();
490       }
491 
492     current = node;
493 
494     while (current != null)
495       {
496         if (list.contains(current))
497           return current;
498 
499         current = current.getParent();
500       }
501 
502     return null;
503   }
504 
505   /**
506    * isNodeRelated
507    *
508    * @param node TODO
509    *
510    * @return boolean
511    */
isNodeRelated(DefaultMutableTreeNode node)512   public boolean isNodeRelated(DefaultMutableTreeNode node)
513   {
514     if (node == null)
515       return false;
516 
517     return node.getRoot() == getRoot();
518   }
519 
520   /**
521    * getDepth
522    *
523    * @return int
524    */
getDepth()525   public int getDepth()
526   {
527     if ((! allowsChildren)
528         || children.size() == 0)
529       return 0;
530 
531     Stack<Integer> stack = new Stack<Integer>();
532     stack.push(new Integer(0));
533     TreeNode node = getChildAt(0);
534     int depth = 0;
535     int current = 1;
536 
537     while (! stack.empty())
538       {
539         if (node.getChildCount() != 0)
540           {
541             node = node.getChildAt(0);
542             stack.push(new Integer(0));
543             current++;
544           }
545         else
546           {
547             if (current > depth)
548               depth = current;
549 
550             int size;
551             int index;
552 
553             do
554               {
555                 node = node.getParent();
556                 size = node.getChildCount();
557                 index = stack.pop().intValue() + 1;
558                 current--;
559               }
560             while (index >= size
561                    && node != this);
562 
563             if (index < size)
564               {
565                 node = node.getChildAt(index);
566                 stack.push(new Integer(index));
567                 current++;
568               }
569           }
570       }
571 
572     return depth;
573   }
574 
575   /**
576    * getLevel
577    *
578    * @return int
579    */
getLevel()580   public int getLevel()
581   {
582     int count = -1;
583     TreeNode current = this;
584 
585     do
586       {
587         current = current.getParent();
588         count++;
589       }
590     while (current != null);
591 
592     return count;
593   }
594 
595   /**
596    * getPathToRoot
597    *
598    * @param node TODO
599    * @param depth TODO
600    *
601    * @return TreeNode[]
602    */
getPathToRoot(TreeNode node, int depth)603   protected TreeNode[] getPathToRoot(TreeNode node, int depth)
604   {
605     if (node == null)
606       {
607         if (depth == 0)
608           return null;
609 
610         return new TreeNode[depth];
611       }
612 
613     TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
614     path[path.length - depth - 1] = node;
615     return path;
616   }
617 
618   /**
619    * getUserObjectPath
620    *
621    * @return Object[]
622    */
getUserObjectPath()623   public Object[] getUserObjectPath()
624   {
625     TreeNode[] path = getPathToRoot(this, 0);
626     Object[] object = new Object[path.length];
627 
628     for (int index = 0; index < path.length; ++index)
629       object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject();
630 
631     return object;
632   }
633 
634   /**
635    * Returns the root node by iterating the parents of this node.
636    *
637    * @return the root node
638    */
getRoot()639   public TreeNode getRoot()
640   {
641     TreeNode current = this;
642     TreeNode check = current.getParent();
643 
644     while (check != null)
645       {
646         current = check;
647         check = current.getParent();
648       }
649 
650     return current;
651   }
652 
653   /**
654    * Tells whether this node is the root node or not.
655    *
656    * @return <code>true</code> if this is the root node,
657    * <code>false</code>otherwise
658    */
isRoot()659   public boolean isRoot()
660   {
661     return parent == null;
662   }
663 
664   /**
665    * getNextNode
666    *
667    * @return DefaultMutableTreeNode
668    */
getNextNode()669   public DefaultMutableTreeNode getNextNode()
670   {
671     // Return first child.
672     if (getChildCount() != 0)
673       return (DefaultMutableTreeNode) getChildAt(0);
674 
675     // Return next sibling (if needed the sibling of some parent).
676     DefaultMutableTreeNode node = this;
677     DefaultMutableTreeNode sibling;
678 
679     do
680       {
681         sibling = node.getNextSibling();
682         node = (DefaultMutableTreeNode) node.getParent();
683       }
684     while (sibling == null &&
685            node != null);
686 
687     // Return sibling.
688     return sibling;
689   }
690 
691   /**
692    * getPreviousNode
693    *
694    * @return DefaultMutableTreeNode
695    */
getPreviousNode()696   public DefaultMutableTreeNode getPreviousNode()
697   {
698     // Return null if no parent.
699     if (parent == null)
700       return null;
701 
702     DefaultMutableTreeNode sibling = getPreviousSibling();
703 
704     // Return parent if no sibling.
705     if (sibling == null)
706       return (DefaultMutableTreeNode) parent;
707 
708     // Return last leaf of sibling.
709     if (sibling.getChildCount() != 0)
710       return sibling.getLastLeaf();
711 
712     // Return sibling.
713     return sibling;
714   }
715 
716   /**
717    * preorderEnumeration
718    *
719    * @return Enumeration
720    */
721   @SuppressWarnings("rawtypes") // Required for API compatibility
preorderEnumeration()722   public Enumeration preorderEnumeration()
723   {
724     return new PreorderEnumeration(this);
725   }
726 
727   /**
728    * postorderEnumeration
729    *
730    * @return Enumeration
731    */
732   @SuppressWarnings("rawtypes") // Required for API compatibility
postorderEnumeration()733   public Enumeration postorderEnumeration()
734   {
735     return new PostorderEnumeration(this);
736   }
737 
738   /**
739    * breadthFirstEnumeration
740    *
741    * @return Enumeration
742    */
743   @SuppressWarnings("rawtypes") // Required for API compatibility
breadthFirstEnumeration()744   public Enumeration breadthFirstEnumeration()
745   {
746     return new BreadthFirstEnumeration(this);
747   }
748 
749   /**
750    * depthFirstEnumeration
751    *
752    * @return Enumeration
753    */
754   @SuppressWarnings("rawtypes") // Required for API compatibility
depthFirstEnumeration()755   public Enumeration depthFirstEnumeration()
756   {
757     return postorderEnumeration();
758   }
759 
760   /**
761    * pathFromAncestorEnumeration
762    *
763    * @param node TODO
764    *
765    * @return Enumeration
766    */
767   @SuppressWarnings("rawtypes") // Required for API compatibility
pathFromAncestorEnumeration(TreeNode node)768   public Enumeration pathFromAncestorEnumeration(TreeNode node)
769   {
770     if (node == null)
771       throw new IllegalArgumentException();
772 
773     TreeNode parent = this;
774     Vector<TreeNode> nodes = new Vector<TreeNode>();
775     nodes.add(this);
776 
777     while (parent != node && parent != null)
778       {
779         parent = parent.getParent();
780         nodes.add(0, parent);
781       }
782 
783     if (parent != node)
784       throw new IllegalArgumentException();
785 
786     return nodes.elements();
787   }
788 
789   /**
790    * Returns <code>true</code> if <code>node</code> is a child of this tree
791    * node, and <code>false</code> otherwise.  If <code>node</code> is
792    * <code>null</code>, this method returns <code>false</code>.
793    *
794    * @param node  the node (<code>null</code> permitted).
795    *
796    * @return A boolean.
797    */
isNodeChild(TreeNode node)798   public boolean isNodeChild(TreeNode node)
799   {
800     if (node == null)
801       return false;
802 
803     return node.getParent() == this;
804   }
805 
806   /**
807    * Returns the first child node belonging to this tree node.
808    *
809    * @return The first child node.
810    *
811    * @throws NoSuchElementException if this tree node has no children.
812    */
getFirstChild()813   public TreeNode getFirstChild()
814   {
815     return children.firstElement();
816   }
817 
818   /**
819    * Returns the last child node belonging to this tree node.
820    *
821    * @return The last child node.
822    *
823    * @throws NoSuchElementException if this tree node has no children.
824    */
getLastChild()825   public TreeNode getLastChild()
826   {
827     return children.lastElement();
828   }
829 
830   /**
831    * Returns the next child after the specified <code>node</code>, or
832    * <code>null</code> if there is no child after the specified
833    * <code>node</code>.
834    *
835    * @param node  a child of this node (<code>null</code> not permitted).
836    *
837    * @return The next child, or <code>null</code>.
838    *
839    * @throws IllegalArgumentException if <code>node</code> is not a child of
840    *     this node, or is <code>null</code>.
841    */
getChildAfter(TreeNode node)842   public TreeNode getChildAfter(TreeNode node)
843   {
844     if (node == null || node.getParent() != this)
845       throw new IllegalArgumentException();
846 
847     int index = getIndex(node) + 1;
848 
849     if (index == getChildCount())
850       return null;
851 
852     return getChildAt(index);
853   }
854 
855   /**
856    * Returns the previous child before the specified <code>node</code>, or
857    * <code>null</code> if there is no child before the specified
858    * <code>node</code>.
859    *
860    * @param node  a child of this node (<code>null</code> not permitted).
861    *
862    * @return The previous child, or <code>null</code>.
863    *
864    * @throws IllegalArgumentException if <code>node</code> is not a child of
865    *     this node, or is <code>null</code>.
866    */
getChildBefore(TreeNode node)867   public TreeNode getChildBefore(TreeNode node)
868   {
869     if (node == null || node.getParent() != this)
870       throw new IllegalArgumentException();
871 
872     int index = getIndex(node) - 1;
873 
874     if (index < 0)
875       return null;
876 
877     return getChildAt(index);
878   }
879 
880   /**
881    * Returns <code>true</code> if this tree node and <code>node</code> share
882    * the same parent.  If <code>node</code> is this tree node, the method
883    * returns <code>true</code> and if <code>node</code> is <code>null</code>
884    * this method returns <code>false</code>.
885    *
886    * @param node  the node (<code>null</code> permitted).
887    *
888    * @return A boolean.
889    */
isNodeSibling(TreeNode node)890   public boolean isNodeSibling(TreeNode node)
891   {
892     if (node == null)
893       return false;
894     if (node == this)
895       return true;
896     return node.getParent() == getParent() && getParent() != null;
897   }
898 
899   /**
900    * Returns the number of siblings for this tree node.  If the tree node has
901    * a parent, this method returns the child count for the parent, otherwise
902    * it returns <code>1</code>.
903    *
904    * @return The sibling count.
905    */
getSiblingCount()906   public int getSiblingCount()
907   {
908     if (parent == null)
909       return 1;
910 
911     return parent.getChildCount();
912   }
913 
914   /**
915    * Returns the next sibling for this tree node.  If this node has no parent,
916    * or this node is the last child of its parent, this method returns
917    * <code>null</code>.
918    *
919    * @return The next sibling, or <code>null</code>.
920    */
getNextSibling()921   public DefaultMutableTreeNode getNextSibling()
922   {
923     if (parent == null)
924       return null;
925 
926     int index = parent.getIndex(this) + 1;
927 
928     if (index == parent.getChildCount())
929       return null;
930 
931     return (DefaultMutableTreeNode) parent.getChildAt(index);
932   }
933 
934   /**
935    * Returns the previous sibling for this tree node.  If this node has no
936    * parent, or this node is the first child of its parent, this method returns
937    * <code>null</code>.
938    *
939    * @return The previous sibling, or <code>null</code>.
940    */
getPreviousSibling()941   public DefaultMutableTreeNode getPreviousSibling()
942   {
943     if (parent == null)
944       return null;
945 
946     int index = parent.getIndex(this) - 1;
947 
948     if (index < 0)
949       return null;
950 
951     return (DefaultMutableTreeNode) parent.getChildAt(index);
952   }
953 
954   /**
955    * Returns <code>true</code> if this tree node is a lead node (that is, it
956    * has no children), and <code>false</otherwise>.
957    *
958    * @return A boolean.
959    */
isLeaf()960   public boolean isLeaf()
961   {
962     return children.size() == 0;
963   }
964 
965   /**
966    * Returns the first leaf node that is a descendant of this node.  Recall
967    * that a node is its own descendant, so if this node has no children then
968    * it is returned as the first leaf.
969    *
970    * @return The first leaf node.
971    */
getFirstLeaf()972   public DefaultMutableTreeNode getFirstLeaf()
973   {
974     TreeNode current = this;
975 
976     while (current.getChildCount() > 0)
977       current = current.getChildAt(0);
978 
979     return (DefaultMutableTreeNode) current;
980   }
981 
982   /**
983    * Returns the last leaf node that is a descendant of this node.  Recall
984    * that a node is its own descendant, so if this node has no children then
985    * it is returned as the last leaf.
986    *
987    * @return The first leaf node.
988    */
getLastLeaf()989   public DefaultMutableTreeNode getLastLeaf()
990   {
991     TreeNode current = this;
992     int size = current.getChildCount();
993 
994     while (size > 0)
995       {
996         current = current.getChildAt(size - 1);
997         size = current.getChildCount();
998       }
999 
1000     return (DefaultMutableTreeNode) current;
1001   }
1002 
1003   /**
1004    * Returns the next leaf node after this tree node.
1005    *
1006    * @return The next leaf node, or <code>null</code>.
1007    */
getNextLeaf()1008   public DefaultMutableTreeNode getNextLeaf()
1009   {
1010     // if there is a next sibling, return its first leaf
1011     DefaultMutableTreeNode sibling = getNextSibling();
1012     if (sibling != null)
1013       return sibling.getFirstLeaf();
1014     // otherwise move up one level and try again...
1015     if (parent != null)
1016       return ((DefaultMutableTreeNode) parent).getNextLeaf();
1017     return null;
1018   }
1019 
1020   /**
1021    * Returns the previous leaf node before this tree node.
1022    *
1023    * @return The previous leaf node, or <code>null</code>.
1024    */
getPreviousLeaf()1025   public DefaultMutableTreeNode getPreviousLeaf()
1026   {
1027     // if there is a previous sibling, return its last leaf
1028     DefaultMutableTreeNode sibling = getPreviousSibling();
1029     if (sibling != null)
1030       return sibling.getLastLeaf();
1031     // otherwise move up one level and try again...
1032     if (parent != null)
1033       return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
1034     return null;
1035   }
1036 
1037   /**
1038    * getLeafCount
1039    *
1040    * @return int
1041    */
getLeafCount()1042   public int getLeafCount()
1043   {
1044     int count = 0;
1045     Enumeration<?> e = depthFirstEnumeration();
1046 
1047     while (e.hasMoreElements())
1048       {
1049         TreeNode current = (TreeNode) e.nextElement();
1050 
1051         if (current.isLeaf())
1052           count++;
1053       }
1054 
1055     return count;
1056   }
1057 
1058   /** Provides an enumeration of a tree in breadth-first traversal
1059    * order.
1060    */
1061   static class BreadthFirstEnumeration implements Enumeration<TreeNode>
1062   {
1063 
1064       LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
1065 
BreadthFirstEnumeration(TreeNode node)1066       BreadthFirstEnumeration(TreeNode node)
1067       {
1068           queue.add(node);
1069       }
1070 
hasMoreElements()1071       public boolean hasMoreElements()
1072       {
1073           return !queue.isEmpty();
1074       }
1075 
nextElement()1076       public TreeNode nextElement()
1077       {
1078           if (queue.isEmpty())
1079               throw new NoSuchElementException("No more elements left.");
1080 
1081           TreeNode node = queue.removeFirst();
1082 
1083 	  @SuppressWarnings("unchecked")
1084           Enumeration<TreeNode> children =
1085             (Enumeration<TreeNode>) node.children();
1086           while (children.hasMoreElements())
1087               queue.add(children.nextElement());
1088 
1089           return node;
1090       }
1091   }
1092 
1093   /** Provides an enumeration of a tree traversing it
1094    * preordered.
1095    */
1096   static class PreorderEnumeration implements Enumeration<TreeNode>
1097   {
1098           TreeNode next;
1099 
1100       Stack<Enumeration<TreeNode>> childrenEnums =
1101         new Stack<Enumeration<TreeNode>>();
1102 
PreorderEnumeration(TreeNode node)1103       PreorderEnumeration(TreeNode node)
1104       {
1105           next = node;
1106 	  @SuppressWarnings("unchecked")
1107 	      Enumeration<TreeNode> children =
1108 	      (Enumeration<TreeNode>) node.children();
1109           childrenEnums.push(children);
1110       }
1111 
hasMoreElements()1112       public boolean hasMoreElements()
1113       {
1114           return next != null;
1115       }
1116 
nextElement()1117       public TreeNode nextElement()
1118       {
1119           if (next == null)
1120               throw new NoSuchElementException("No more elements left.");
1121 
1122           TreeNode current = next;
1123 
1124           Enumeration<TreeNode> children = childrenEnums.peek();
1125 
1126           // Retrieves the next element.
1127           next = traverse(children);
1128 
1129           return current;
1130       }
1131 
traverse(Enumeration<TreeNode> children)1132       private TreeNode traverse(Enumeration<TreeNode> children)
1133       {
1134           // If more children are available step down.
1135           if (children.hasMoreElements())
1136           {
1137               TreeNode child = children.nextElement();
1138 	      @SuppressWarnings("unchecked")
1139 		  Enumeration<TreeNode> grandchildren =
1140 		  (Enumeration<TreeNode>) child.children();
1141               childrenEnums.push(grandchildren);
1142 
1143               return child;
1144           }
1145 
1146           // If no children are left, we return to a higher level.
1147           childrenEnums.pop();
1148 
1149           // If there are no more levels left, there is no next
1150           // element to return.
1151           if (childrenEnums.isEmpty())
1152               return null;
1153           else
1154           {
1155               return traverse(childrenEnums.peek());
1156           }
1157       }
1158    }
1159 
1160   /** Provides an enumeration of a tree traversing it
1161    * postordered (= depth-first).
1162    */
1163    static class PostorderEnumeration implements Enumeration<TreeNode>
1164    {
1165 
1166        Stack<TreeNode> nodes = new Stack<TreeNode>();
1167        Stack<Enumeration<TreeNode>> childrenEnums =
1168          new Stack<Enumeration<TreeNode>>();
1169 
PostorderEnumeration(TreeNode node)1170        PostorderEnumeration(TreeNode node)
1171        {
1172            nodes.push(node);
1173 	   @SuppressWarnings("unchecked")
1174 	       Enumeration<TreeNode> children =
1175 	       (Enumeration<TreeNode>) node.children();
1176            childrenEnums.push(children);
1177        }
1178 
hasMoreElements()1179        public boolean hasMoreElements()
1180        {
1181            return !nodes.isEmpty();
1182        }
1183 
nextElement()1184        public TreeNode nextElement()
1185        {
1186            if (nodes.isEmpty())
1187                throw new NoSuchElementException("No more elements left!");
1188 
1189            Enumeration<TreeNode> children = childrenEnums.peek();
1190 
1191            return traverse(children);
1192        }
1193 
traverse(Enumeration<TreeNode> children)1194        private TreeNode traverse(Enumeration<TreeNode> children)
1195        {
1196            if (children.hasMoreElements())
1197            {
1198                TreeNode node = children.nextElement();
1199                nodes.push(node);
1200 
1201 	       @SuppressWarnings("unchecked")
1202 		   Enumeration<TreeNode> newChildren =
1203 		   (Enumeration<TreeNode>) node.children();
1204                childrenEnums.push(newChildren);
1205 
1206                return traverse(newChildren);
1207            }
1208            else
1209            {
1210                childrenEnums.pop();
1211 
1212                // Returns the node whose children
1213                // have all been visited. (= postorder)
1214                TreeNode next = nodes.peek();
1215                nodes.pop();
1216 
1217                return next;
1218            }
1219        }
1220 
1221     }
1222 
1223 }
1224