Source for javax.swing.tree.DefaultMutableTreeNode

   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 EMPTY_ENUMERATION =
  71:     EmptyEnumeration.getInstance();
  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 children = new Vector();
  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 = (MutableTreeNode) 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 list = new ArrayList();
 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 stack = new Stack();
 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 = ((Integer) 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 nodes = new Vector();
 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()
 891:             && getParent() != null);
 892:   }
 893: 
 894:   /**
 895:    * Returns the number of siblings for this tree node.  If the tree node has
 896:    * a parent, this method returns the child count for the parent, otherwise
 897:    * it returns <code>1</code>.
 898:    *
 899:    * @return The sibling count.
 900:    */
 901:   public int getSiblingCount()
 902:   {
 903:     if (parent == null)
 904:       return 1;
 905: 
 906:     return parent.getChildCount();
 907:   }
 908: 
 909:   /**
 910:    * Returns the next sibling for this tree node.  If this node has no parent,
 911:    * or this node is the last child of its parent, this method returns 
 912:    * <code>null</code>.  
 913:    *
 914:    * @return The next sibling, or <code>null</code>.
 915:    */
 916:   public DefaultMutableTreeNode getNextSibling()
 917:   {
 918:     if (parent == null)
 919:       return null;
 920: 
 921:     int index = parent.getIndex(this) + 1;
 922:     
 923:     if (index == parent.getChildCount())
 924:       return null;
 925: 
 926:     return (DefaultMutableTreeNode) parent.getChildAt(index);
 927:   }
 928: 
 929:   /**
 930:    * Returns the previous sibling for this tree node.  If this node has no 
 931:    * parent, or this node is the first child of its parent, this method returns 
 932:    * <code>null</code>.  
 933:    *
 934:    * @return The previous sibling, or <code>null</code>.
 935:    */
 936:   public DefaultMutableTreeNode getPreviousSibling()
 937:   {
 938:     if (parent == null)
 939:       return null;
 940: 
 941:     int index = parent.getIndex(this) - 1;
 942: 
 943:     if (index < 0)
 944:       return null;
 945: 
 946:     return (DefaultMutableTreeNode) parent.getChildAt(index);
 947:   }
 948: 
 949:   /**
 950:    * Returns <code>true</code> if this tree node is a lead node (that is, it 
 951:    * has no children), and <code>false</otherwise>.
 952:    *
 953:    * @return A boolean.
 954:    */
 955:   public boolean isLeaf()
 956:   {
 957:     return children.size() == 0;
 958:   }
 959: 
 960:   /**
 961:    * Returns the first leaf node that is a descendant of this node.  Recall 
 962:    * that a node is its own descendant, so if this node has no children then 
 963:    * it is returned as the first leaf.
 964:    *
 965:    * @return The first leaf node.
 966:    */
 967:   public DefaultMutableTreeNode getFirstLeaf()
 968:   {
 969:     TreeNode current = this;
 970:     
 971:     while (current.getChildCount() > 0)
 972:       current = current.getChildAt(0);
 973: 
 974:     return (DefaultMutableTreeNode) current;
 975:   }
 976: 
 977:   /**
 978:    * Returns the last leaf node that is a descendant of this node.  Recall 
 979:    * that a node is its own descendant, so if this node has no children then 
 980:    * it is returned as the last leaf.
 981:    *
 982:    * @return The first leaf node.
 983:    */
 984:   public DefaultMutableTreeNode getLastLeaf()
 985:   {
 986:     TreeNode current = this;
 987:     int size = current.getChildCount();
 988:     
 989:     while (size > 0)
 990:       {
 991:         current = current.getChildAt(size - 1);
 992:         size = current.getChildCount();
 993:       }
 994: 
 995:     return (DefaultMutableTreeNode) current;
 996:   }
 997: 
 998:   /**
 999:    * Returns the next leaf node after this tree node. 
1000:    *
1001:    * @return The next leaf node, or <code>null</code>.
1002:    */
1003:   public DefaultMutableTreeNode getNextLeaf()
1004:   {
1005:     // if there is a next sibling, return its first leaf
1006:     DefaultMutableTreeNode sibling = getNextSibling();
1007:     if (sibling != null)
1008:       return sibling.getFirstLeaf();
1009:     // otherwise move up one level and try again...
1010:     if (parent != null)
1011:       return ((DefaultMutableTreeNode) parent).getNextLeaf();
1012:     return null;
1013:   }
1014: 
1015:   /**
1016:    * Returns the previous leaf node before this tree node.
1017:    *
1018:    * @return The previous leaf node, or <code>null</code>.
1019:    */
1020:   public DefaultMutableTreeNode getPreviousLeaf()
1021:   {
1022:     // if there is a previous sibling, return its last leaf
1023:     DefaultMutableTreeNode sibling = getPreviousSibling();
1024:     if (sibling != null)
1025:       return sibling.getLastLeaf();
1026:     // otherwise move up one level and try again...
1027:     if (parent != null)
1028:       return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
1029:     return null;
1030:   }
1031: 
1032:   /**
1033:    * getLeafCount
1034:    *
1035:    * @return int
1036:    */
1037:   public int getLeafCount()
1038:   {
1039:     int count = 0;
1040:     Enumeration e = depthFirstEnumeration();
1041: 
1042:     while (e.hasMoreElements())
1043:       {
1044:         TreeNode current = (TreeNode) e.nextElement();
1045:         
1046:         if (current.isLeaf())
1047:           count++;
1048:       }
1049: 
1050:     return count;
1051:   }
1052: 
1053:   /** Provides an enumeration of a tree in breadth-first traversal
1054:    * order.
1055:    */
1056:   static class BreadthFirstEnumeration implements Enumeration
1057:   {
1058: 
1059:       LinkedList queue = new LinkedList();
1060: 
1061:       BreadthFirstEnumeration(TreeNode node)
1062:       {
1063:           queue.add(node);
1064:       }
1065: 
1066:       public boolean hasMoreElements()
1067:       {
1068:           return !queue.isEmpty();
1069:       }
1070: 
1071:       public Object nextElement()
1072:       {
1073:           if(queue.isEmpty())
1074:               throw new NoSuchElementException("No more elements left.");
1075: 
1076:           TreeNode node = (TreeNode) queue.removeFirst();
1077: 
1078:           Enumeration children = node.children();
1079:           while (children.hasMoreElements())
1080:               queue.add(children.nextElement());
1081: 
1082:           return node;
1083:       }
1084:   }
1085: 
1086:   /** Provides an enumeration of a tree traversing it
1087:    * preordered.
1088:    */
1089:   static class PreorderEnumeration implements Enumeration
1090:   {
1091:       TreeNode next;
1092: 
1093:       Stack childrenEnums = new Stack();
1094: 
1095:       PreorderEnumeration(TreeNode node)
1096:       {
1097:           next = node;
1098:           childrenEnums.push(node.children());
1099:       }
1100: 
1101:       public boolean hasMoreElements()
1102:       {
1103:           return next != null;
1104:       }
1105: 
1106:       public Object nextElement()
1107:       {
1108:           if( next == null )
1109:               throw new NoSuchElementException("No more elements left.");
1110: 
1111:           Object current = next;
1112: 
1113:           Enumeration children = (Enumeration) childrenEnums.peek();
1114: 
1115:           // Retrieves the next element.
1116:           next = traverse(children);
1117: 
1118:           return current;
1119:       }
1120: 
1121:       private TreeNode traverse(Enumeration children)
1122:       {
1123:           // If more children are available step down.
1124:           if( children.hasMoreElements() )
1125:           {
1126:               TreeNode child = (TreeNode) children.nextElement();
1127:               childrenEnums.push(child.children());
1128: 
1129:               return child;
1130:           }
1131:           
1132:           // If no children are left, we return to a higher level.
1133:           childrenEnums.pop();
1134: 
1135:           // If there are no more levels left, there is no next
1136:           // element to return.
1137:           if ( childrenEnums.isEmpty() )
1138:               return null;
1139:           else
1140:           {
1141:               return traverse((Enumeration) childrenEnums.peek());
1142:           }
1143:       }
1144:    }
1145: 
1146:   /** Provides an enumeration of a tree traversing it
1147:    * postordered (= depth-first).
1148:    */
1149:    static class PostorderEnumeration implements Enumeration
1150:    {
1151: 
1152:        Stack nodes = new Stack();
1153:        Stack childrenEnums = new Stack();
1154: 
1155:        PostorderEnumeration(TreeNode node)
1156:        {
1157:            nodes.push(node);
1158:            childrenEnums.push(node.children());
1159:        }
1160: 
1161:        public boolean hasMoreElements()
1162:        {
1163:            return !nodes.isEmpty();
1164:        }
1165: 
1166:        public Object nextElement()
1167:        {
1168:            if( nodes.isEmpty() )
1169:                throw new NoSuchElementException("No more elements left!");
1170: 
1171:            Enumeration children = (Enumeration) childrenEnums.peek();
1172: 
1173:            return traverse(children);
1174:        }
1175: 
1176:        private Object traverse(Enumeration children)
1177:        {
1178:            if ( children.hasMoreElements() )
1179:            {
1180:                TreeNode node = (TreeNode) children.nextElement();
1181:                nodes.push(node);
1182: 
1183:                Enumeration newChildren = node.children();
1184:                childrenEnums.push(newChildren);
1185: 
1186:                return traverse(newChildren);
1187:            }
1188:            else
1189:            {
1190:                childrenEnums.pop();
1191: 
1192:                // Returns the node whose children
1193:                // have all been visited. (= postorder)
1194:                Object next = nodes.peek();
1195:                nodes.pop();
1196: 
1197:                return next;
1198:            }
1199:        }
1200: 
1201:     }
1202: 
1203: }