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<TreeNode> EMPTY_ENUMERATION =
  71:     new EmptyEnumeration<TreeNode>();
  72: 
  73:   /**
  74:    * The parent of this node (possibly <code>null</code>).
  75:    */
  76:   protected MutableTreeNode parent;
  77: 
  78:   /**
  79:    * The child nodes for this node (may be empty).
  80:    */
  81:   protected Vector<MutableTreeNode> children = new Vector<MutableTreeNode>();
  82: 
  83:   /**
  84:    * userObject
  85:    */
  86:   protected transient Object userObject;
  87: 
  88:   /**
  89:    * allowsChildren
  90:    */
  91:   protected boolean allowsChildren;
  92: 
  93:   /**
  94:    * Creates a <code>DefaultMutableTreeNode</code> object.
  95:    * This is equivalent to <code>DefaultMutableTreeNode(null, true)</code>.
  96:    */
  97:   public DefaultMutableTreeNode()
  98:   {
  99:     this(null, true);
 100:   }
 101: 
 102:   /**
 103:    * Creates a <code>DefaultMutableTreeNode</code> object with the given
 104:    * user object attached to it. This is equivalent to
 105:    * <code>DefaultMutableTreeNode(userObject, true)</code>.
 106:    *
 107:    * @param userObject the user object (<code>null</code> permitted).
 108:    */
 109:   public DefaultMutableTreeNode(Object userObject)
 110:   {
 111:     this(userObject, true);
 112:   }
 113: 
 114:   /**
 115:    * Creates a <code>DefaultMutableTreeNode</code> object with the given
 116:    * user object attached to it.
 117:    *
 118:    * @param userObject the user object (<code>null</code> permitted).
 119:    * @param allowsChildren <code>true</code> if the code allows to add child
 120:    * nodes, <code>false</code> otherwise
 121:    */
 122:   public DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
 123:   {
 124:     this.userObject = userObject;
 125:     this.allowsChildren = allowsChildren;
 126:   }
 127: 
 128:   /**
 129:    * Returns a clone of the node.  The clone contains a shallow copy of the
 130:    * user object, and does not copy the parent node or the child nodes.
 131:    *
 132:    * @return A clone of the node.
 133:    */
 134:   public Object clone()
 135:   {
 136:     return new DefaultMutableTreeNode(this.userObject, this.allowsChildren);
 137:   }
 138: 
 139:   /**
 140:    * Returns a string representation of the node.  This implementation returns
 141:    * <code>getUserObject().toString()</code>, or <code>null</code> if there
 142:    * is no user object.
 143:    *
 144:    * @return A string representation of the node (possibly <code>null</code>).
 145:    */
 146:   public String toString()
 147:   {
 148:     if (userObject == null)
 149:       return null;
 150: 
 151:     return userObject.toString();
 152:   }
 153: 
 154:   /**
 155:    * Adds a new child node to this node and sets this node as the parent of
 156:    * the child node.  The child node must not be an ancestor of this node.
 157:    * If the tree uses the {@link DefaultTreeModel}, you must subsequently
 158:    * call {@link DefaultTreeModel#reload(TreeNode)}.
 159:    *
 160:    * @param child the child node (<code>null</code> not permitted).
 161:    *
 162:    * @throws IllegalStateException if {@link #getAllowsChildren()} returns
 163:    *     <code>false</code>.
 164:    * @throws IllegalArgumentException if {@link #isNodeAncestor} returns
 165:    *     <code>true</code>.
 166:    * @throws IllegalArgumentException if <code>child</code> is
 167:    *     <code>null</code>.
 168:    */
 169:   public void add(MutableTreeNode child)
 170:   {
 171:     if (! allowsChildren)
 172:       throw new IllegalStateException();
 173: 
 174:     if (child == null)
 175:       throw new IllegalArgumentException();
 176: 
 177:     if (isNodeAncestor(child))
 178:       throw new IllegalArgumentException("Cannot add ancestor node.");
 179: 
 180:     children.add(child);
 181:     child.setParent(this);
 182:   }
 183: 
 184:   /**
 185:    * Returns the parent node of this node.
 186:    *
 187:    * @return The parent node (possibly <code>null</code>).
 188:    */
 189:   public TreeNode getParent()
 190:   {
 191:     return parent;
 192:   }
 193: 
 194:   /**
 195:    * Removes the child with the given index from this node.
 196:    *
 197:    * @param index the index (in the range <code>0</code> to
 198:    *     <code>getChildCount() - 1</code>).
 199:    *
 200:    * @throws ArrayIndexOutOfBoundsException if <code>index</code> is outside
 201:    *         the valid range.
 202:    */
 203:   public void remove(int index)
 204:   {
 205:     MutableTreeNode child = children.remove(index);
 206:     child.setParent(null);
 207:   }
 208: 
 209:   /**
 210:    * Removes the given child from this node and sets its parent to
 211:    * <code>null</code>.
 212:    *
 213:    * @param node the child node (<code>null</code> not permitted).
 214:    *
 215:    * @throws IllegalArgumentException if <code>node</code> is not a child of
 216:    *     this node.
 217:    * @throws IllegalArgumentException if <code>node</code> is null.
 218:    */
 219:   public void remove(MutableTreeNode node)
 220:   {
 221:     if (node == null)
 222:       throw new IllegalArgumentException("Null 'node' argument.");
 223:     if (node.getParent() != this)
 224:       throw new IllegalArgumentException(
 225:           "The given 'node' is not a child of this node.");
 226:     children.remove(node);
 227:     node.setParent(null);
 228:   }
 229: 
 230:   /**
 231:    * writeObject
 232:    *
 233:    * @param stream the output stream
 234:    *
 235:    * @exception IOException If an error occurs
 236:    */
 237:   private void writeObject(ObjectOutputStream stream)
 238:     throws IOException
 239:   {
 240:     // TODO: Implement me.
 241:   }
 242: 
 243:   /**
 244:    * readObject
 245:    *
 246:    * @param stream the input stream
 247:    *
 248:    * @exception IOException If an error occurs
 249:    * @exception ClassNotFoundException TODO
 250:    */
 251:   private void readObject(ObjectInputStream stream)
 252:     throws IOException, ClassNotFoundException
 253:   {
 254:     // TODO: Implement me.
 255:   }
 256: 
 257:   /**
 258:    * Inserts given child node at the given index.
 259:    *
 260:    * @param node the child node (<code>null</code> not permitted).
 261:    * @param index the index.
 262:    *
 263:    * @throws IllegalArgumentException if <code>node</code> is
 264:    *     </code>null</code>.
 265:    */
 266:   public void insert(MutableTreeNode node, int index)
 267:   {
 268:     if (! allowsChildren)
 269:       throw new IllegalStateException();
 270: 
 271:     if (node == null)
 272:       throw new IllegalArgumentException("Null 'node' argument.");
 273: 
 274:     if (isNodeAncestor(node))
 275:       throw new IllegalArgumentException("Cannot insert ancestor node.");
 276: 
 277:     children.insertElementAt(node, index);
 278:   }
 279: 
 280:   /**
 281:    * Returns a path to this node from the root.
 282:    *
 283:    * @return an array of tree nodes
 284:    */
 285:   public TreeNode[] getPath()
 286:   {
 287:     return getPathToRoot(this, 0);
 288:   }
 289: 
 290:   /**
 291:    * Returns an enumeration containing all children of this node.
 292:    * <code>EMPTY_ENUMERATION</code> is returned if this node has no children.
 293:    *
 294:    * @return an enumeration of tree nodes
 295:    */
 296:   @SuppressWarnings("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: }