OSDN Git Service

GNU Classpath import (libgcj-snapshot-20100921).
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / tree / DefaultMutableTreeNode.java
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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("unchecked") // Required for API compatibility
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
394   public Object getUserObject()
395   {
396     return userObject;
397   }
398
399   /**
400    * Removes this node from its parent.
401    */
402   public void removeFromParent()
403   {
404     parent.remove(this);
405     parent = null;
406   }
407
408   /**
409    * Removes all child nodes from this node.
410    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
659   public boolean isRoot()
660   {
661     return parent == null;
662   }
663
664   /**
665    * getNextNode
666    *
667    * @return DefaultMutableTreeNode
668    */
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    */
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("unchecked") // Required for API compatibility
722   public Enumeration preorderEnumeration()
723   {
724     return new PreorderEnumeration(this);
725   }
726
727   /**
728    * postorderEnumeration
729    *
730    * @return Enumeration
731    */
732   @SuppressWarnings("unchecked") // Required for API compatibility
733   public Enumeration postorderEnumeration()
734   {
735     return new PostorderEnumeration(this);
736   }
737
738   /**
739    * breadthFirstEnumeration
740    *
741    * @return Enumeration
742    */
743   @SuppressWarnings("unchecked") // Required for API compatibility
744   public Enumeration breadthFirstEnumeration()
745   {
746     return new BreadthFirstEnumeration(this);
747   }
748
749   /**
750    * depthFirstEnumeration
751    *
752    * @return Enumeration
753    */
754   @SuppressWarnings("unchecked") // Required for API compatibility
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("unchecked") // Required for API compatibility
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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
1066       BreadthFirstEnumeration(TreeNode node)
1067       {
1068           queue.add(node);
1069       }
1070
1071       public boolean hasMoreElements()
1072       {
1073           return !queue.isEmpty();
1074       }
1075
1076       @SuppressWarnings("unchecked")
1077       public TreeNode nextElement()
1078       {
1079           if (queue.isEmpty())
1080               throw new NoSuchElementException("No more elements left.");
1081
1082           TreeNode node = queue.removeFirst();
1083
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
1103       @SuppressWarnings("unchecked")
1104       PreorderEnumeration(TreeNode node)
1105       {
1106           next = node;
1107           childrenEnums.push((Enumeration<TreeNode>) node.children());
1108       }
1109
1110       public boolean hasMoreElements()
1111       {
1112           return next != null;
1113       }
1114
1115       public TreeNode nextElement()
1116       {
1117           if (next == null)
1118               throw new NoSuchElementException("No more elements left.");
1119
1120           TreeNode current = next;
1121
1122           Enumeration<TreeNode> children = childrenEnums.peek();
1123
1124           // Retrieves the next element.
1125           next = traverse(children);
1126
1127           return current;
1128       }
1129
1130       @SuppressWarnings("unchecked")
1131       private TreeNode traverse(Enumeration<TreeNode> children)
1132       {
1133           // If more children are available step down.
1134           if (children.hasMoreElements())
1135           {
1136               TreeNode child = children.nextElement();
1137               childrenEnums.push((Enumeration<TreeNode>) child.children());
1138
1139               return child;
1140           }
1141           
1142           // If no children are left, we return to a higher level.
1143           childrenEnums.pop();
1144
1145           // If there are no more levels left, there is no next
1146           // element to return.
1147           if (childrenEnums.isEmpty())
1148               return null;
1149           else
1150           {
1151               return traverse(childrenEnums.peek());
1152           }
1153       }
1154    }
1155
1156   /** Provides an enumeration of a tree traversing it
1157    * postordered (= depth-first).
1158    */
1159    static class PostorderEnumeration implements Enumeration<TreeNode>
1160    {
1161
1162        Stack<TreeNode> nodes = new Stack<TreeNode>();
1163        Stack<Enumeration<TreeNode>> childrenEnums =
1164          new Stack<Enumeration<TreeNode>>();
1165
1166        @SuppressWarnings("unchecked")
1167        PostorderEnumeration(TreeNode node)
1168        {
1169            nodes.push(node);
1170            childrenEnums.push((Enumeration<TreeNode>) node.children());
1171        }
1172
1173        public boolean hasMoreElements()
1174        {
1175            return !nodes.isEmpty();
1176        }
1177
1178        public TreeNode nextElement()
1179        {
1180            if (nodes.isEmpty())
1181                throw new NoSuchElementException("No more elements left!");
1182
1183            Enumeration<TreeNode> children = childrenEnums.peek();
1184
1185            return traverse(children);
1186        }
1187
1188        @SuppressWarnings("unchecked")
1189        private TreeNode traverse(Enumeration<TreeNode> children)
1190        {
1191            if (children.hasMoreElements())
1192            {
1193                TreeNode node = children.nextElement();
1194                nodes.push(node);
1195
1196                Enumeration<TreeNode> newChildren =
1197                  (Enumeration<TreeNode>) node.children();
1198                childrenEnums.push(newChildren);
1199
1200                return traverse(newChildren);
1201            }
1202            else
1203            {
1204                childrenEnums.pop();
1205
1206                // Returns the node whose children
1207                // have all been visited. (= postorder)
1208                TreeNode next = nodes.peek();
1209                nodes.pop();
1210
1211                return next;
1212            }
1213        }
1214
1215     }
1216
1217 }