001/* DefaultMutableTreeNode.java --
002   Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.tree;
040
041import gnu.java.util.EmptyEnumeration;
042
043import java.io.IOException;
044import java.io.ObjectInputStream;
045import java.io.ObjectOutputStream;
046import java.io.Serializable;
047import java.util.ArrayList;
048import java.util.Enumeration;
049import java.util.LinkedList;
050import java.util.NoSuchElementException;
051import java.util.Stack;
052import java.util.Vector;
053
054
055/**
056 * A default implementation of the {@link MutableTreeNode} interface.
057 *
058 * @author Andrew Selkirk
059 * @author Robert Schuster (robertschuster@fsfe.org)
060 */
061public class DefaultMutableTreeNode
062  implements Cloneable, MutableTreeNode, Serializable
063{
064  private static final long serialVersionUID = -4298474751201349152L;
065
066  /**
067   * An empty enumeration, returned by {@link #children()} if a node has no
068   * children.
069   */
070  public static final Enumeration<TreeNode> EMPTY_ENUMERATION =
071    new EmptyEnumeration<TreeNode>();
072
073  /**
074   * The parent of this node (possibly <code>null</code>).
075   */
076  protected MutableTreeNode parent;
077
078  /**
079   * The child nodes for this node (may be empty).
080   */
081  protected Vector<MutableTreeNode> children = new Vector<MutableTreeNode>();
082
083  /**
084   * userObject
085   */
086  protected transient Object userObject;
087
088  /**
089   * allowsChildren
090   */
091  protected boolean allowsChildren;
092
093  /**
094   * Creates a <code>DefaultMutableTreeNode</code> object.
095   * This is equivalent to <code>DefaultMutableTreeNode(null, true)</code>.
096   */
097  public DefaultMutableTreeNode()
098  {
099    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("rawtypes") // 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("rawtypes") // 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("rawtypes") // 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("rawtypes") // 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("rawtypes") // 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("rawtypes") // 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      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
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
1112      public boolean hasMoreElements()
1113      {
1114          return next != null;
1115      }
1116
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
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
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
1179       public boolean hasMoreElements()
1180       {
1181           return !nodes.isEmpty();
1182       }
1183
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
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}