OSDN Git Service

libjava/ChangeLog:
[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   public Enumeration children()
297   {
298     if (children.size() == 0)
299       return EMPTY_ENUMERATION;
300     
301     return children.elements();
302   }
303
304   /**
305    * Set the parent node for this node.
306    *
307    * @param node the parent node
308    */
309   public void setParent(MutableTreeNode node)
310   {
311     parent = node;
312   }
313
314   /**
315    * Returns the child node at a given index.
316    *
317    * @param index the index
318    *
319    * @return the child node
320    */
321   public TreeNode getChildAt(int index)
322   {
323     return (TreeNode) children.elementAt(index);
324   }
325
326   /**
327    * Returns the number of children of this node.
328    *
329    * @return the number of children
330    */
331   public int getChildCount()
332   {
333     return children.size();
334   }
335
336   /**
337    * Returns the index of the specified child node, or -1 if the node is not
338    * in fact a child of this node.
339    * 
340    * @param node  the node (<code>null</code> not permitted).
341    * 
342    * @return The index of the specified child node, or -1.
343    * 
344    * @throws IllegalArgumentException if <code>node</code> is <code>null</code>.
345    */
346   public int getIndex(TreeNode node)
347   {
348     if (node == null)
349       throw new IllegalArgumentException("Null 'node' argument.");
350     return children.indexOf(node);
351   }
352
353   /**
354    * Sets the flag that controls whether or not this node allows the addition / 
355    * insertion of child nodes.  If the flag is set to <code>false</code>, any
356    * existing children are removed.
357    *
358    * @param allowsChildren  the flag.
359    */
360   public void setAllowsChildren(boolean allowsChildren)
361   {
362     if (!allowsChildren)
363       removeAllChildren();
364     this.allowsChildren = allowsChildren;
365   }
366
367   /**
368    * getAllowsChildren
369    *
370    * @return boolean
371    */
372   public boolean getAllowsChildren()
373   {
374     return allowsChildren;
375   }
376
377   /**
378    * Sets the user object for this node
379    *
380    * @param userObject the user object
381    */
382   public void setUserObject(Object userObject)
383   {
384     this.userObject = userObject;
385   }
386
387   /**
388    * Returns the user object attached to this node. <code>null</code> is
389    * returned when no user object is set.
390    *
391    * @return the user object
392    */
393   public Object getUserObject()
394   {
395     return userObject;
396   }
397
398   /**
399    * Removes this node from its parent.
400    */
401   public void removeFromParent()
402   {
403     parent.remove(this);
404     parent = null;
405   }
406
407   /**
408    * Removes all child nodes from this node.
409    */
410   public void removeAllChildren()
411   {
412     for (int i = getChildCount() - 1; i >= 0; i--)
413       remove(i);
414   }
415
416   /**
417    * Returns <code>true</code> if <code>node</code> is an ancestor of this
418    * tree node, and <code>false</code> otherwise.  An ancestor node is any of:
419    * <ul>
420    * <li>this tree node;</li>
421    * <li>the parent node (if there is one);</li>
422    * <li>any ancestor of the parent node;</li>
423    * </ul>
424    * If <code>node</code> is <code>null</code>, this method returns 
425    * <code>false</code>.
426    * 
427    * @param node  the node (<code>null</code> permitted).
428    *
429    * @return A boolean.
430    */
431   public boolean isNodeAncestor(TreeNode node)
432   {
433     if (node == null)
434       return false;
435
436     TreeNode current = this;
437
438     while (current != null && current != node)
439       current = current.getParent();
440
441     return current == node;
442   }
443
444   /**
445    * Returns <code>true</code> if <code>node</code> is a descendant of this
446    * tree node, and <code>false</code> otherwise.  A descendant node is any of:
447    * <ul>
448    * <li>this tree node;</li>
449    * <li>the child nodes belonging to this tree node, if there are any;</li>
450    * <li>any descendants of the child nodes;</li>
451    * </ul>
452    * If <code>node</code> is <code>null</code>, this method returns 
453    * <code>false</code>.
454    * 
455    * @param node  the node (<code>null</code> permitted).
456    *
457    * @return A boolean.
458    */
459   public boolean isNodeDescendant(DefaultMutableTreeNode node)
460   {
461     if (node == null)
462       return false;
463
464     TreeNode current = node;
465     
466     while (current != null
467            && current != this)
468       current = current.getParent();
469
470     return current == this;
471   }
472
473   /**
474    * getSharedAncestor
475    *
476    * @param node TODO
477    *
478    * @return TreeNode
479    */
480   public TreeNode getSharedAncestor(DefaultMutableTreeNode node)
481   {
482     TreeNode current = this;
483     ArrayList<TreeNode> list = new ArrayList<TreeNode>();
484
485     while (current != null)
486       {
487         list.add(current);
488         current = current.getParent();
489       }
490
491     current = node;
492
493     while (current != null)
494       {
495         if (list.contains(current))
496           return current;
497
498         current = current.getParent();
499       }
500
501     return null;
502   }
503
504   /**
505    * isNodeRelated
506    *
507    * @param node TODO
508    *
509    * @return boolean
510    */
511   public boolean isNodeRelated(DefaultMutableTreeNode node)
512   {
513     if (node == null)
514       return false;
515
516     return node.getRoot() == getRoot();
517   }
518
519   /**
520    * getDepth
521    *
522    * @return int
523    */
524   public int getDepth()
525   {
526     if ((! allowsChildren)
527         || children.size() == 0)
528       return 0;
529
530     Stack<Integer> stack = new Stack<Integer>();
531     stack.push(new Integer(0));
532     TreeNode node = getChildAt(0);
533     int depth = 0;
534     int current = 1;
535     
536     while (! stack.empty())
537       {
538         if (node.getChildCount() != 0)
539           {
540             node = node.getChildAt(0);
541             stack.push(new Integer(0));
542             current++;
543           }
544         else
545           {
546             if (current > depth)
547               depth = current;
548
549             int size;
550             int index;
551             
552             do
553               {
554                 node = node.getParent();
555                 size = node.getChildCount();
556                 index = stack.pop().intValue() + 1;
557                 current--;
558               }
559             while (index >= size
560                    && node != this);
561
562             if (index < size)
563               {
564                 node = node.getChildAt(index);
565                 stack.push(new Integer(index));
566                 current++;
567               }
568           }
569       }
570
571     return depth;
572   }
573
574   /**
575    * getLevel
576    *
577    * @return int
578    */
579   public int getLevel()
580   {
581     int count = -1;
582     TreeNode current = this;
583
584     do
585       {
586         current = current.getParent();
587         count++;
588       }
589     while (current != null);
590
591     return count;
592   }
593
594   /**
595    * getPathToRoot
596    *
597    * @param node TODO
598    * @param depth TODO
599    *
600    * @return TreeNode[]
601    */
602   protected TreeNode[] getPathToRoot(TreeNode node, int depth)
603   {
604     if (node == null)
605       {
606         if (depth == 0)
607           return null;
608         
609         return new TreeNode[depth];
610       }
611
612     TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
613     path[path.length - depth - 1] = node;
614     return path;
615   }
616
617   /**
618    * getUserObjectPath
619    *
620    * @return Object[]
621    */
622   public Object[] getUserObjectPath()
623   {
624     TreeNode[] path = getPathToRoot(this, 0);
625     Object[] object = new Object[path.length];
626     
627     for (int index = 0; index < path.length; ++index)
628       object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject();
629
630     return object;
631   }
632
633   /**
634    * Returns the root node by iterating the parents of this node.
635    *
636    * @return the root node
637    */
638   public TreeNode getRoot()
639   {
640     TreeNode current = this;
641     TreeNode check = current.getParent();
642     
643     while (check != null)
644       {
645         current = check;
646         check = current.getParent();
647       }
648
649     return current;
650   }
651
652   /**
653    * Tells whether this node is the root node or not.
654    *
655    * @return <code>true</code> if this is the root node,
656    * <code>false</code>otherwise
657    */
658   public boolean isRoot()
659   {
660     return parent == null;
661   }
662
663   /**
664    * getNextNode
665    *
666    * @return DefaultMutableTreeNode
667    */
668   public DefaultMutableTreeNode getNextNode()
669   {
670     // Return first child.
671     if (getChildCount() != 0)
672       return (DefaultMutableTreeNode) getChildAt(0);
673
674     // Return next sibling (if needed the sibling of some parent).
675     DefaultMutableTreeNode node = this;
676     DefaultMutableTreeNode sibling;
677     
678     do
679       {
680         sibling = node.getNextSibling();
681         node = (DefaultMutableTreeNode) node.getParent();
682       }
683     while (sibling == null &&
684            node != null);
685     
686     // Return sibling.
687     return sibling;
688   }
689
690   /**
691    * getPreviousNode
692    *
693    * @return DefaultMutableTreeNode
694    */
695   public DefaultMutableTreeNode getPreviousNode()
696   {
697     // Return null if no parent.
698     if (parent == null)
699       return null;
700     
701     DefaultMutableTreeNode sibling = getPreviousSibling();
702
703     // Return parent if no sibling.
704     if (sibling == null)
705       return (DefaultMutableTreeNode) parent;
706
707     // Return last leaf of sibling.
708     if (sibling.getChildCount() != 0)
709       return sibling.getLastLeaf();
710
711     // Return sibling.
712     return sibling;
713   }
714
715   /**
716    * preorderEnumeration
717    *
718    * @return Enumeration
719    */
720   public Enumeration preorderEnumeration()
721   {
722     return new PreorderEnumeration(this);
723   }
724
725   /**
726    * postorderEnumeration
727    *
728    * @return Enumeration
729    */
730   public Enumeration postorderEnumeration()
731   {
732     return new PostorderEnumeration(this);
733   }
734
735   /**
736    * breadthFirstEnumeration
737    *
738    * @return Enumeration
739    */
740   public Enumeration breadthFirstEnumeration()
741   {
742     return new BreadthFirstEnumeration(this);
743   }
744
745   /**
746    * depthFirstEnumeration
747    *
748    * @return Enumeration
749    */
750   public Enumeration depthFirstEnumeration()
751   {
752     return postorderEnumeration();
753   }
754
755   /**
756    * pathFromAncestorEnumeration
757    *
758    * @param node TODO
759    *
760    * @return Enumeration
761    */
762   public Enumeration pathFromAncestorEnumeration(TreeNode node)
763   {
764     if (node == null)
765       throw new IllegalArgumentException();
766     
767     TreeNode parent = this;
768     Vector<TreeNode> nodes = new Vector<TreeNode>();
769     nodes.add(this);
770
771     while (parent != node && parent != null)
772       {
773         parent = parent.getParent();
774         nodes.add(0, parent);
775       }
776
777     if (parent != node)
778       throw new IllegalArgumentException();
779     
780     return nodes.elements();
781   }
782
783   /**
784    * Returns <code>true</code> if <code>node</code> is a child of this tree 
785    * node, and <code>false</code> otherwise.  If <code>node</code> is 
786    * <code>null</code>, this method returns <code>false</code>.
787    *
788    * @param node  the node (<code>null</code> permitted).
789    *
790    * @return A boolean.
791    */
792   public boolean isNodeChild(TreeNode node)
793   {
794     if (node == null)
795       return false;
796
797     return node.getParent() == this;
798   }
799
800   /**
801    * Returns the first child node belonging to this tree node.
802    *
803    * @return The first child node.
804    * 
805    * @throws NoSuchElementException if this tree node has no children.
806    */
807   public TreeNode getFirstChild()
808   {
809     return (TreeNode) children.firstElement();
810   }
811
812   /**
813    * Returns the last child node belonging to this tree node.
814    *
815    * @return The last child node.
816    * 
817    * @throws NoSuchElementException if this tree node has no children.
818    */
819   public TreeNode getLastChild()
820   {
821     return (TreeNode) children.lastElement();
822   }
823
824   /**
825    * Returns the next child after the specified <code>node</code>, or 
826    * <code>null</code> if there is no child after the specified 
827    * <code>node</code>.
828    *
829    * @param node  a child of this node (<code>null</code> not permitted).
830    *
831    * @return The next child, or <code>null</code>.
832    * 
833    * @throws IllegalArgumentException if <code>node</code> is not a child of 
834    *     this node, or is <code>null</code>.
835    */
836   public TreeNode getChildAfter(TreeNode node)
837   {
838     if (node == null || node.getParent() != this)
839       throw new IllegalArgumentException();
840
841     int index = getIndex(node) + 1;
842
843     if (index == getChildCount())
844       return null;
845
846     return getChildAt(index);
847   }
848
849   /**
850    * Returns the previous child before the specified <code>node</code>, or 
851    * <code>null</code> if there is no child before the specified 
852    * <code>node</code>.
853    *
854    * @param node  a child of this node (<code>null</code> not permitted).
855    *
856    * @return The previous child, or <code>null</code>.
857    * 
858    * @throws IllegalArgumentException if <code>node</code> is not a child of 
859    *     this node, or is <code>null</code>.
860    */
861   public TreeNode getChildBefore(TreeNode node)
862   {
863     if (node == null || node.getParent() != this)
864       throw new IllegalArgumentException();
865
866     int index = getIndex(node) - 1;
867
868     if (index < 0)
869       return null;
870
871     return getChildAt(index);
872   }
873
874   /**
875    * Returns <code>true</code> if this tree node and <code>node</code> share
876    * the same parent.  If <code>node</code> is this tree node, the method
877    * returns <code>true</code> and if <code>node</code> is <code>null</code>
878    * this method returns <code>false</code>.
879    *
880    * @param node  the node (<code>null</code> permitted).
881    *
882    * @return A boolean.
883    */
884   public boolean isNodeSibling(TreeNode node)
885   {
886     if (node == null)
887       return false;
888     if (node == this)
889       return true;
890     return node.getParent() == getParent() && getParent() != null;
891   }
892
893   /**
894    * Returns the number of siblings for this tree node.  If the tree node has
895    * a parent, this method returns the child count for the parent, otherwise
896    * it returns <code>1</code>.
897    *
898    * @return The sibling count.
899    */
900   public int getSiblingCount()
901   {
902     if (parent == null)
903       return 1;
904
905     return parent.getChildCount();
906   }
907
908   /**
909    * Returns the next sibling for this tree node.  If this node has no parent,
910    * or this node is the last child of its parent, this method returns 
911    * <code>null</code>.  
912    *
913    * @return The next sibling, or <code>null</code>.
914    */
915   public DefaultMutableTreeNode getNextSibling()
916   {
917     if (parent == null)
918       return null;
919
920     int index = parent.getIndex(this) + 1;
921     
922     if (index == parent.getChildCount())
923       return null;
924
925     return (DefaultMutableTreeNode) parent.getChildAt(index);
926   }
927
928   /**
929    * Returns the previous sibling for this tree node.  If this node has no 
930    * parent, or this node is the first child of its parent, this method returns 
931    * <code>null</code>.  
932    *
933    * @return The previous sibling, or <code>null</code>.
934    */
935   public DefaultMutableTreeNode getPreviousSibling()
936   {
937     if (parent == null)
938       return null;
939
940     int index = parent.getIndex(this) - 1;
941
942     if (index < 0)
943       return null;
944
945     return (DefaultMutableTreeNode) parent.getChildAt(index);
946   }
947
948   /**
949    * Returns <code>true</code> if this tree node is a lead node (that is, it 
950    * has no children), and <code>false</otherwise>.
951    *
952    * @return A boolean.
953    */
954   public boolean isLeaf()
955   {
956     return children.size() == 0;
957   }
958
959   /**
960    * Returns the first leaf node that is a descendant of this node.  Recall 
961    * that a node is its own descendant, so if this node has no children then 
962    * it is returned as the first leaf.
963    *
964    * @return The first leaf node.
965    */
966   public DefaultMutableTreeNode getFirstLeaf()
967   {
968     TreeNode current = this;
969     
970     while (current.getChildCount() > 0)
971       current = current.getChildAt(0);
972
973     return (DefaultMutableTreeNode) current;
974   }
975
976   /**
977    * Returns the last leaf node that is a descendant of this node.  Recall 
978    * that a node is its own descendant, so if this node has no children then 
979    * it is returned as the last leaf.
980    *
981    * @return The first leaf node.
982    */
983   public DefaultMutableTreeNode getLastLeaf()
984   {
985     TreeNode current = this;
986     int size = current.getChildCount();
987     
988     while (size > 0)
989       {
990         current = current.getChildAt(size - 1);
991         size = current.getChildCount();
992       }
993
994     return (DefaultMutableTreeNode) current;
995   }
996
997   /**
998    * Returns the next leaf node after this tree node. 
999    *
1000    * @return The next leaf node, or <code>null</code>.
1001    */
1002   public DefaultMutableTreeNode getNextLeaf()
1003   {
1004     // if there is a next sibling, return its first leaf
1005     DefaultMutableTreeNode sibling = getNextSibling();
1006     if (sibling != null)
1007       return sibling.getFirstLeaf();
1008     // otherwise move up one level and try again...
1009     if (parent != null)
1010       return ((DefaultMutableTreeNode) parent).getNextLeaf();
1011     return null;
1012   }
1013
1014   /**
1015    * Returns the previous leaf node before this tree node.
1016    *
1017    * @return The previous leaf node, or <code>null</code>.
1018    */
1019   public DefaultMutableTreeNode getPreviousLeaf()
1020   {
1021     // if there is a previous sibling, return its last leaf
1022     DefaultMutableTreeNode sibling = getPreviousSibling();
1023     if (sibling != null)
1024       return sibling.getLastLeaf();
1025     // otherwise move up one level and try again...
1026     if (parent != null)
1027       return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
1028     return null;
1029   }
1030
1031   /**
1032    * getLeafCount
1033    *
1034    * @return int
1035    */
1036   public int getLeafCount()
1037   {
1038     int count = 0;
1039     Enumeration e = depthFirstEnumeration();
1040
1041     while (e.hasMoreElements())
1042       {
1043         TreeNode current = (TreeNode) e.nextElement();
1044         
1045         if (current.isLeaf())
1046           count++;
1047       }
1048
1049     return count;
1050   }
1051
1052   /** Provides an enumeration of a tree in breadth-first traversal
1053    * order.
1054    */
1055   static class BreadthFirstEnumeration implements Enumeration<TreeNode>
1056   {
1057
1058       LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
1059
1060       BreadthFirstEnumeration(TreeNode node)
1061       {
1062           queue.add(node);
1063       }
1064
1065       public boolean hasMoreElements()
1066       {
1067           return !queue.isEmpty();
1068       }
1069
1070       @SuppressWarnings("unchecked")
1071       public TreeNode nextElement()
1072       {
1073           if (queue.isEmpty())
1074               throw new NoSuchElementException("No more elements left.");
1075
1076           TreeNode node = queue.removeFirst();
1077
1078           Enumeration<TreeNode> children =
1079             (Enumeration<TreeNode>) node.children();
1080           while (children.hasMoreElements())
1081               queue.add(children.nextElement());
1082
1083           return node;
1084       }
1085   }
1086
1087   /** Provides an enumeration of a tree traversing it
1088    * preordered.
1089    */
1090   static class PreorderEnumeration implements Enumeration<TreeNode>
1091   {
1092           TreeNode next;
1093
1094       Stack<Enumeration<TreeNode>> childrenEnums =
1095         new Stack<Enumeration<TreeNode>>();
1096
1097       @SuppressWarnings("unchecked")
1098       PreorderEnumeration(TreeNode node)
1099       {
1100           next = node;
1101           childrenEnums.push((Enumeration<TreeNode>) node.children());
1102       }
1103
1104       public boolean hasMoreElements()
1105       {
1106           return next != null;
1107       }
1108
1109       public TreeNode nextElement()
1110       {
1111           if (next == null)
1112               throw new NoSuchElementException("No more elements left.");
1113
1114           TreeNode current = next;
1115
1116           Enumeration<TreeNode> children = childrenEnums.peek();
1117
1118           // Retrieves the next element.
1119           next = traverse(children);
1120
1121           return current;
1122       }
1123
1124       @SuppressWarnings("unchecked")
1125       private TreeNode traverse(Enumeration<TreeNode> children)
1126       {
1127           // If more children are available step down.
1128           if (children.hasMoreElements())
1129           {
1130               TreeNode child = children.nextElement();
1131               childrenEnums.push((Enumeration<TreeNode>) child.children());
1132
1133               return child;
1134           }
1135           
1136           // If no children are left, we return to a higher level.
1137           childrenEnums.pop();
1138
1139           // If there are no more levels left, there is no next
1140           // element to return.
1141           if (childrenEnums.isEmpty())
1142               return null;
1143           else
1144           {
1145               return traverse(childrenEnums.peek());
1146           }
1147       }
1148    }
1149
1150   /** Provides an enumeration of a tree traversing it
1151    * postordered (= depth-first).
1152    */
1153    static class PostorderEnumeration implements Enumeration<TreeNode>
1154    {
1155
1156        Stack<TreeNode> nodes = new Stack<TreeNode>();
1157        Stack<Enumeration<TreeNode>> childrenEnums =
1158          new Stack<Enumeration<TreeNode>>();
1159
1160        @SuppressWarnings("unchecked")
1161        PostorderEnumeration(TreeNode node)
1162        {
1163            nodes.push(node);
1164            childrenEnums.push((Enumeration<TreeNode>) node.children());
1165        }
1166
1167        public boolean hasMoreElements()
1168        {
1169            return !nodes.isEmpty();
1170        }
1171
1172        public TreeNode nextElement()
1173        {
1174            if (nodes.isEmpty())
1175                throw new NoSuchElementException("No more elements left!");
1176
1177            Enumeration<TreeNode> children = childrenEnums.peek();
1178
1179            return traverse(children);
1180        }
1181
1182        @SuppressWarnings("unchecked")
1183        private TreeNode traverse(Enumeration<TreeNode> children)
1184        {
1185            if (children.hasMoreElements())
1186            {
1187                TreeNode node = children.nextElement();
1188                nodes.push(node);
1189
1190                Enumeration<TreeNode> newChildren =
1191                  (Enumeration<TreeNode>) node.children();
1192                childrenEnums.push(newChildren);
1193
1194                return traverse(newChildren);
1195            }
1196            else
1197            {
1198                childrenEnums.pop();
1199
1200                // Returns the node whose children
1201                // have all been visited. (= postorder)
1202                TreeNode next = nodes.peek();
1203                nodes.pop();
1204
1205                return next;
1206            }
1207        }
1208
1209     }
1210
1211 }