1 /* 2 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.tree; 27 // ISSUE: this class depends on nothing in AWT -- move to java.util? 28 29 import java.beans.Transient; 30 import java.io.*; 31 import java.util.*; 32 33 34 /** 35 * A <code>DefaultMutableTreeNode</code> is a general-purpose node in a tree data 36 * structure. 37 * For examples of using default mutable tree nodes, see 38 * <a 39 href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a> 40 * in <em>The Java Tutorial.</em> 41 * 42 * <p> 43 * 44 * A tree node may have at most one parent and 0 or more children. 45 * <code>DefaultMutableTreeNode</code> provides operations for examining and modifying a 46 * node's parent and children and also operations for examining the tree that 47 * the node is a part of. A node's tree is the set of all nodes that can be 48 * reached by starting at the node and following all the possible links to 49 * parents and children. A node with no parent is the root of its tree; a 50 * node with no children is a leaf. A tree may consist of many subtrees, 51 * each node acting as the root for its own subtree. 52 * <p> 53 * This class provides enumerations for efficiently traversing a tree or 54 * subtree in various orders or for following the path between two nodes. 55 * A <code>DefaultMutableTreeNode</code> may also hold a reference to a user object, the 56 * use of which is left to the user. Asking a <code>DefaultMutableTreeNode</code> for its 57 * string representation with <code>toString()</code> returns the string 58 * representation of its user object. 59 * <p> 60 * <b>This is not a thread safe class.</b>If you intend to use 61 * a DefaultMutableTreeNode (or a tree of TreeNodes) in more than one thread, you 62 * need to do your own synchronizing. A good convention to adopt is 63 * synchronizing on the root node of a tree. 64 * <p> 65 * While DefaultMutableTreeNode implements the MutableTreeNode interface and 66 * will allow you to add in any implementation of MutableTreeNode not all 67 * of the methods in DefaultMutableTreeNode will be applicable to all 68 * MutableTreeNodes implementations. Especially with some of the enumerations 69 * that are provided, using some of these methods assumes the 70 * DefaultMutableTreeNode contains only DefaultMutableNode instances. All 71 * of the TreeNode/MutableTreeNode methods will behave as defined no 72 * matter what implementations are added. 73 * 74 * <p> 75 * <strong>Warning:</strong> 76 * Serialized objects of this class will not be compatible with 77 * future Swing releases. The current serialization support is 78 * appropriate for short term storage or RMI between applications running 79 * the same version of Swing. As of 1.4, support for long term storage 80 * of all JavaBeans™ 81 * has been added to the <code>java.beans</code> package. 82 * Please see {@link java.beans.XMLEncoder}. 83 * 84 * @see MutableTreeNode 85 * 86 * @author Rob Davis 87 */ 88 public class DefaultMutableTreeNode implements Cloneable, 89 MutableTreeNode, Serializable 90 { 91 private static final long serialVersionUID = -4298474751201349152L; 92 93 /** 94 * An enumeration that is always empty. This is used when an enumeration 95 * of a leaf node's children is requested. 96 */ 97 static public final Enumeration<TreeNode> EMPTY_ENUMERATION 98 = Collections.emptyEnumeration(); 99 100 /** this node's parent, or null if this node has no parent */ 101 protected MutableTreeNode parent; 102 103 /** array of children, may be null if this node has no children */ 104 protected Vector children; 105 106 /** optional user object */ 107 transient protected Object userObject; 108 109 /** true if the node is able to have children */ 110 protected boolean allowsChildren; 111 112 113 /** 114 * Creates a tree node that has no parent and no children, but which 115 * allows children. 116 */ 117 public DefaultMutableTreeNode() { 118 this(null); 119 } 120 121 /** 122 * Creates a tree node with no parent, no children, but which allows 123 * children, and initializes it with the specified user object. 124 * 125 * @param userObject an Object provided by the user that constitutes 126 * the node's data 127 */ 128 public DefaultMutableTreeNode(Object userObject) { 129 this(userObject, true); 130 } 131 132 /** 133 * Creates a tree node with no parent, no children, initialized with 134 * the specified user object, and that allows children only if 135 * specified. 136 * 137 * @param userObject an Object provided by the user that constitutes 138 * the node's data 139 * @param allowsChildren if true, the node is allowed to have child 140 * nodes -- otherwise, it is always a leaf node 141 */ 142 public DefaultMutableTreeNode(Object userObject, boolean allowsChildren) { 143 super(); 144 parent = null; 145 this.allowsChildren = allowsChildren; 146 this.userObject = userObject; 147 } 148 149 150 // 151 // Primitives 152 // 153 154 /** 155 * Removes <code>newChild</code> from its present parent (if it has a 156 * parent), sets the child's parent to this node, and then adds the child 157 * to this node's child array at index <code>childIndex</code>. 158 * <code>newChild</code> must not be null and must not be an ancestor of 159 * this node. 160 * 161 * @param newChild the MutableTreeNode to insert under this node 162 * @param childIndex the index in this node's child array 163 * where this node is to be inserted 164 * @exception ArrayIndexOutOfBoundsException if 165 * <code>childIndex</code> is out of bounds 166 * @exception IllegalArgumentException if 167 * <code>newChild</code> is null or is an 168 * ancestor of this node 169 * @exception IllegalStateException if this node does not allow 170 * children 171 * @see #isNodeDescendant 172 */ 173 public void insert(MutableTreeNode newChild, int childIndex) { 174 if (!allowsChildren) { 175 throw new IllegalStateException("node does not allow children"); 176 } else if (newChild == null) { 177 throw new IllegalArgumentException("new child is null"); 178 } else if (isNodeAncestor(newChild)) { 179 throw new IllegalArgumentException("new child is an ancestor"); 180 } 181 182 MutableTreeNode oldParent = (MutableTreeNode)newChild.getParent(); 183 184 if (oldParent != null) { 185 oldParent.remove(newChild); 186 } 187 newChild.setParent(this); 188 if (children == null) { 189 children = new Vector(); 190 } 191 children.insertElementAt(newChild, childIndex); 192 } 193 194 /** 195 * Removes the child at the specified index from this node's children 196 * and sets that node's parent to null. The child node to remove 197 * must be a <code>MutableTreeNode</code>. 198 * 199 * @param childIndex the index in this node's child array 200 * of the child to remove 201 * @exception ArrayIndexOutOfBoundsException if 202 * <code>childIndex</code> is out of bounds 203 */ 204 public void remove(int childIndex) { 205 MutableTreeNode child = (MutableTreeNode)getChildAt(childIndex); 206 children.removeElementAt(childIndex); 207 child.setParent(null); 208 } 209 210 /** 211 * Sets this node's parent to <code>newParent</code> but does not 212 * change the parent's child array. This method is called from 213 * <code>insert()</code> and <code>remove()</code> to 214 * reassign a child's parent, it should not be messaged from anywhere 215 * else. 216 * 217 * @param newParent this node's new parent 218 */ 219 @Transient 220 public void setParent(MutableTreeNode newParent) { 221 parent = newParent; 222 } 223 224 /** 225 * Returns this node's parent or null if this node has no parent. 226 * 227 * @return this node's parent TreeNode, or null if this node has no parent 228 */ 229 public TreeNode getParent() { 230 return parent; 231 } 232 233 /** 234 * Returns the child at the specified index in this node's child array. 235 * 236 * @param index an index into this node's child array 237 * @exception ArrayIndexOutOfBoundsException if <code>index</code> 238 * is out of bounds 239 * @return the TreeNode in this node's child array at the specified index 240 */ 241 public TreeNode getChildAt(int index) { 242 if (children == null) { 243 throw new ArrayIndexOutOfBoundsException("node has no children"); 244 } 245 return (TreeNode)children.elementAt(index); 246 } 247 248 /** 249 * Returns the number of children of this node. 250 * 251 * @return an int giving the number of children of this node 252 */ 253 public int getChildCount() { 254 if (children == null) { 255 return 0; 256 } else { 257 return children.size(); 258 } 259 } 260 261 /** 262 * Returns the index of the specified child in this node's child array. 263 * If the specified node is not a child of this node, returns 264 * <code>-1</code>. This method performs a linear search and is O(n) 265 * where n is the number of children. 266 * 267 * @param aChild the TreeNode to search for among this node's children 268 * @exception IllegalArgumentException if <code>aChild</code> 269 * is null 270 * @return an int giving the index of the node in this node's child 271 * array, or <code>-1</code> if the specified node is a not 272 * a child of this node 273 */ 274 public int getIndex(TreeNode aChild) { 275 if (aChild == null) { 276 throw new IllegalArgumentException("argument is null"); 277 } 278 279 if (!isNodeChild(aChild)) { 280 return -1; 281 } 282 return children.indexOf(aChild); // linear search 283 } 284 285 /** 286 * Creates and returns a forward-order enumeration of this node's 287 * children. Modifying this node's child array invalidates any child 288 * enumerations created before the modification. 289 * 290 * @return an Enumeration of this node's children 291 */ 292 public Enumeration children() { 293 if (children == null) { 294 return EMPTY_ENUMERATION; 295 } else { 296 return children.elements(); 297 } 298 } 299 300 /** 301 * Determines whether or not this node is allowed to have children. 302 * If <code>allows</code> is false, all of this node's children are 303 * removed. 304 * <p> 305 * Note: By default, a node allows children. 306 * 307 * @param allows true if this node is allowed to have children 308 */ 309 public void setAllowsChildren(boolean allows) { 310 if (allows != allowsChildren) { 311 allowsChildren = allows; 312 if (!allowsChildren) { 313 removeAllChildren(); 314 } 315 } 316 } 317 318 /** 319 * Returns true if this node is allowed to have children. 320 * 321 * @return true if this node allows children, else false 322 */ 323 public boolean getAllowsChildren() { 324 return allowsChildren; 325 } 326 327 /** 328 * Sets the user object for this node to <code>userObject</code>. 329 * 330 * @param userObject the Object that constitutes this node's 331 * user-specified data 332 * @see #getUserObject 333 * @see #toString 334 */ 335 public void setUserObject(Object userObject) { 336 this.userObject = userObject; 337 } 338 339 /** 340 * Returns this node's user object. 341 * 342 * @return the Object stored at this node by the user 343 * @see #setUserObject 344 * @see #toString 345 */ 346 public Object getUserObject() { 347 return userObject; 348 } 349 350 351 // 352 // Derived methods 353 // 354 355 /** 356 * Removes the subtree rooted at this node from the tree, giving this 357 * node a null parent. Does nothing if this node is the root of its 358 * tree. 359 */ 360 public void removeFromParent() { 361 MutableTreeNode parent = (MutableTreeNode)getParent(); 362 if (parent != null) { 363 parent.remove(this); 364 } 365 } 366 367 /** 368 * Removes <code>aChild</code> from this node's child array, giving it a 369 * null parent. 370 * 371 * @param aChild a child of this node to remove 372 * @exception IllegalArgumentException if <code>aChild</code> 373 * is null or is not a child of this node 374 */ 375 public void remove(MutableTreeNode aChild) { 376 if (aChild == null) { 377 throw new IllegalArgumentException("argument is null"); 378 } 379 380 if (!isNodeChild(aChild)) { 381 throw new IllegalArgumentException("argument is not a child"); 382 } 383 remove(getIndex(aChild)); // linear search 384 } 385 386 /** 387 * Removes all of this node's children, setting their parents to null. 388 * If this node has no children, this method does nothing. 389 */ 390 public void removeAllChildren() { 391 for (int i = getChildCount()-1; i >= 0; i--) { 392 remove(i); 393 } 394 } 395 396 /** 397 * Removes <code>newChild</code> from its parent and makes it a child of 398 * this node by adding it to the end of this node's child array. 399 * 400 * @see #insert 401 * @param newChild node to add as a child of this node 402 * @exception IllegalArgumentException if <code>newChild</code> 403 * is null 404 * @exception IllegalStateException if this node does not allow 405 * children 406 */ 407 public void add(MutableTreeNode newChild) { 408 if(newChild != null && newChild.getParent() == this) 409 insert(newChild, getChildCount() - 1); 410 else 411 insert(newChild, getChildCount()); 412 } 413 414 415 416 // 417 // Tree Queries 418 // 419 420 /** 421 * Returns true if <code>anotherNode</code> is an ancestor of this node 422 * -- if it is this node, this node's parent, or an ancestor of this 423 * node's parent. (Note that a node is considered an ancestor of itself.) 424 * If <code>anotherNode</code> is null, this method returns false. This 425 * operation is at worst O(h) where h is the distance from the root to 426 * this node. 427 * 428 * @see #isNodeDescendant 429 * @see #getSharedAncestor 430 * @param anotherNode node to test as an ancestor of this node 431 * @return true if this node is a descendant of <code>anotherNode</code> 432 */ 433 public boolean isNodeAncestor(TreeNode anotherNode) { 434 if (anotherNode == null) { 435 return false; 436 } 437 438 TreeNode ancestor = this; 439 440 do { 441 if (ancestor == anotherNode) { 442 return true; 443 } 444 } while((ancestor = ancestor.getParent()) != null); 445 446 return false; 447 } 448 449 /** 450 * Returns true if <code>anotherNode</code> is a descendant of this node 451 * -- if it is this node, one of this node's children, or a descendant of 452 * one of this node's children. Note that a node is considered a 453 * descendant of itself. If <code>anotherNode</code> is null, returns 454 * false. This operation is at worst O(h) where h is the distance from the 455 * root to <code>anotherNode</code>. 456 * 457 * @see #isNodeAncestor 458 * @see #getSharedAncestor 459 * @param anotherNode node to test as descendant of this node 460 * @return true if this node is an ancestor of <code>anotherNode</code> 461 */ 462 public boolean isNodeDescendant(DefaultMutableTreeNode anotherNode) { 463 if (anotherNode == null) 464 return false; 465 466 return anotherNode.isNodeAncestor(this); 467 } 468 469 /** 470 * Returns the nearest common ancestor to this node and <code>aNode</code>. 471 * Returns null, if no such ancestor exists -- if this node and 472 * <code>aNode</code> are in different trees or if <code>aNode</code> is 473 * null. A node is considered an ancestor of itself. 474 * 475 * @see #isNodeAncestor 476 * @see #isNodeDescendant 477 * @param aNode node to find common ancestor with 478 * @return nearest ancestor common to this node and <code>aNode</code>, 479 * or null if none 480 */ 481 public TreeNode getSharedAncestor(DefaultMutableTreeNode aNode) { 482 if (aNode == this) { 483 return this; 484 } else if (aNode == null) { 485 return null; 486 } 487 488 int level1, level2, diff; 489 TreeNode node1, node2; 490 491 level1 = getLevel(); 492 level2 = aNode.getLevel(); 493 494 if (level2 > level1) { 495 diff = level2 - level1; 496 node1 = aNode; 497 node2 = this; 498 } else { 499 diff = level1 - level2; 500 node1 = this; 501 node2 = aNode; 502 } 503 504 // Go up the tree until the nodes are at the same level 505 while (diff > 0) { 506 node1 = node1.getParent(); 507 diff--; 508 } 509 510 // Move up the tree until we find a common ancestor. Since we know 511 // that both nodes are at the same level, we won't cross paths 512 // unknowingly (if there is a common ancestor, both nodes hit it in 513 // the same iteration). 514 515 do { 516 if (node1 == node2) { 517 return node1; 518 } 519 node1 = node1.getParent(); 520 node2 = node2.getParent(); 521 } while (node1 != null);// only need to check one -- they're at the 522 // same level so if one is null, the other is 523 524 if (node1 != null || node2 != null) { 525 throw new Error ("nodes should be null"); 526 } 527 528 return null; 529 } 530 531 532 /** 533 * Returns true if and only if <code>aNode</code> is in the same tree 534 * as this node. Returns false if <code>aNode</code> is null. 535 * 536 * @see #getSharedAncestor 537 * @see #getRoot 538 * @return true if <code>aNode</code> is in the same tree as this node; 539 * false if <code>aNode</code> is null 540 */ 541 public boolean isNodeRelated(DefaultMutableTreeNode aNode) { 542 return (aNode != null) && (getRoot() == aNode.getRoot()); 543 } 544 545 546 /** 547 * Returns the depth of the tree rooted at this node -- the longest 548 * distance from this node to a leaf. If this node has no children, 549 * returns 0. This operation is much more expensive than 550 * <code>getLevel()</code> because it must effectively traverse the entire 551 * tree rooted at this node. 552 * 553 * @see #getLevel 554 * @return the depth of the tree whose root is this node 555 */ 556 public int getDepth() { 557 Object last = null; 558 Enumeration enum_ = breadthFirstEnumeration(); 559 560 while (enum_.hasMoreElements()) { 561 last = enum_.nextElement(); 562 } 563 564 if (last == null) { 565 throw new Error ("nodes should be null"); 566 } 567 568 return ((DefaultMutableTreeNode)last).getLevel() - getLevel(); 569 } 570 571 572 573 /** 574 * Returns the number of levels above this node -- the distance from 575 * the root to this node. If this node is the root, returns 0. 576 * 577 * @see #getDepth 578 * @return the number of levels above this node 579 */ 580 public int getLevel() { 581 TreeNode ancestor; 582 int levels = 0; 583 584 ancestor = this; 585 while((ancestor = ancestor.getParent()) != null){ 586 levels++; 587 } 588 589 return levels; 590 } 591 592 593 /** 594 * Returns the path from the root, to get to this node. The last 595 * element in the path is this node. 596 * 597 * @return an array of TreeNode objects giving the path, where the 598 * first element in the path is the root and the last 599 * element is this node. 600 */ 601 public TreeNode[] getPath() { 602 return getPathToRoot(this, 0); 603 } 604 605 /** 606 * Builds the parents of node up to and including the root node, 607 * where the original node is the last element in the returned array. 608 * The length of the returned array gives the node's depth in the 609 * tree. 610 * 611 * @param aNode the TreeNode to get the path for 612 * @param depth an int giving the number of steps already taken towards 613 * the root (on recursive calls), used to size the returned array 614 * @return an array of TreeNodes giving the path from the root to the 615 * specified node 616 */ 617 protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) { 618 TreeNode[] retNodes; 619 620 /* Check for null, in case someone passed in a null node, or 621 they passed in an element that isn't rooted at root. */ 622 if(aNode == null) { 623 if(depth == 0) 624 return null; 625 else 626 retNodes = new TreeNode[depth]; 627 } 628 else { 629 depth++; 630 retNodes = getPathToRoot(aNode.getParent(), depth); 631 retNodes[retNodes.length - depth] = aNode; 632 } 633 return retNodes; 634 } 635 636 /** 637 * Returns the user object path, from the root, to get to this node. 638 * If some of the TreeNodes in the path have null user objects, the 639 * returned path will contain nulls. 640 */ 641 public Object[] getUserObjectPath() { 642 TreeNode[] realPath = getPath(); 643 Object[] retPath = new Object[realPath.length]; 644 645 for(int counter = 0; counter < realPath.length; counter++) 646 retPath[counter] = ((DefaultMutableTreeNode)realPath[counter]) 647 .getUserObject(); 648 return retPath; 649 } 650 651 /** 652 * Returns the root of the tree that contains this node. The root is 653 * the ancestor with a null parent. 654 * 655 * @see #isNodeAncestor 656 * @return the root of the tree that contains this node 657 */ 658 public TreeNode getRoot() { 659 TreeNode ancestor = this; 660 TreeNode previous; 661 662 do { 663 previous = ancestor; 664 ancestor = ancestor.getParent(); 665 } while (ancestor != null); 666 667 return previous; 668 } 669 670 671 /** 672 * Returns true if this node is the root of the tree. The root is 673 * the only node in the tree with a null parent; every tree has exactly 674 * one root. 675 * 676 * @return true if this node is the root of its tree 677 */ 678 public boolean isRoot() { 679 return getParent() == null; 680 } 681 682 683 /** 684 * Returns the node that follows this node in a preorder traversal of this 685 * node's tree. Returns null if this node is the last node of the 686 * traversal. This is an inefficient way to traverse the entire tree; use 687 * an enumeration, instead. 688 * 689 * @see #preorderEnumeration 690 * @return the node that follows this node in a preorder traversal, or 691 * null if this node is last 692 */ 693 public DefaultMutableTreeNode getNextNode() { 694 if (getChildCount() == 0) { 695 // No children, so look for nextSibling 696 DefaultMutableTreeNode nextSibling = getNextSibling(); 697 698 if (nextSibling == null) { 699 DefaultMutableTreeNode aNode = (DefaultMutableTreeNode)getParent(); 700 701 do { 702 if (aNode == null) { 703 return null; 704 } 705 706 nextSibling = aNode.getNextSibling(); 707 if (nextSibling != null) { 708 return nextSibling; 709 } 710 711 aNode = (DefaultMutableTreeNode)aNode.getParent(); 712 } while(true); 713 } else { 714 return nextSibling; 715 } 716 } else { 717 return (DefaultMutableTreeNode)getChildAt(0); 718 } 719 } 720 721 722 /** 723 * Returns the node that precedes this node in a preorder traversal of 724 * this node's tree. Returns <code>null</code> if this node is the 725 * first node of the traversal -- the root of the tree. 726 * This is an inefficient way to 727 * traverse the entire tree; use an enumeration, instead. 728 * 729 * @see #preorderEnumeration 730 * @return the node that precedes this node in a preorder traversal, or 731 * null if this node is the first 732 */ 733 public DefaultMutableTreeNode getPreviousNode() { 734 DefaultMutableTreeNode previousSibling; 735 DefaultMutableTreeNode myParent = (DefaultMutableTreeNode)getParent(); 736 737 if (myParent == null) { 738 return null; 739 } 740 741 previousSibling = getPreviousSibling(); 742 743 if (previousSibling != null) { 744 if (previousSibling.getChildCount() == 0) 745 return previousSibling; 746 else 747 return previousSibling.getLastLeaf(); 748 } else { 749 return myParent; 750 } 751 } 752 753 /** 754 * Creates and returns an enumeration that traverses the subtree rooted at 755 * this node in preorder. The first node returned by the enumeration's 756 * <code>nextElement()</code> method is this node.<P> 757 * 758 * Modifying the tree by inserting, removing, or moving a node invalidates 759 * any enumerations created before the modification. 760 * 761 * @see #postorderEnumeration 762 * @return an enumeration for traversing the tree in preorder 763 */ 764 public Enumeration preorderEnumeration() { 765 return new PreorderEnumeration(this); 766 } 767 768 /** 769 * Creates and returns an enumeration that traverses the subtree rooted at 770 * this node in postorder. The first node returned by the enumeration's 771 * <code>nextElement()</code> method is the leftmost leaf. This is the 772 * same as a depth-first traversal.<P> 773 * 774 * Modifying the tree by inserting, removing, or moving a node invalidates 775 * any enumerations created before the modification. 776 * 777 * @see #depthFirstEnumeration 778 * @see #preorderEnumeration 779 * @return an enumeration for traversing the tree in postorder 780 */ 781 public Enumeration postorderEnumeration() { 782 return new PostorderEnumeration(this); 783 } 784 785 /** 786 * Creates and returns an enumeration that traverses the subtree rooted at 787 * this node in breadth-first order. The first node returned by the 788 * enumeration's <code>nextElement()</code> method is this node.<P> 789 * 790 * Modifying the tree by inserting, removing, or moving a node invalidates 791 * any enumerations created before the modification. 792 * 793 * @see #depthFirstEnumeration 794 * @return an enumeration for traversing the tree in breadth-first order 795 */ 796 public Enumeration breadthFirstEnumeration() { 797 return new BreadthFirstEnumeration(this); 798 } 799 800 /** 801 * Creates and returns an enumeration that traverses the subtree rooted at 802 * this node in depth-first order. The first node returned by the 803 * enumeration's <code>nextElement()</code> method is the leftmost leaf. 804 * This is the same as a postorder traversal.<P> 805 * 806 * Modifying the tree by inserting, removing, or moving a node invalidates 807 * any enumerations created before the modification. 808 * 809 * @see #breadthFirstEnumeration 810 * @see #postorderEnumeration 811 * @return an enumeration for traversing the tree in depth-first order 812 */ 813 public Enumeration depthFirstEnumeration() { 814 return postorderEnumeration(); 815 } 816 817 /** 818 * Creates and returns an enumeration that follows the path from 819 * <code>ancestor</code> to this node. The enumeration's 820 * <code>nextElement()</code> method first returns <code>ancestor</code>, 821 * then the child of <code>ancestor</code> that is an ancestor of this 822 * node, and so on, and finally returns this node. Creation of the 823 * enumeration is O(m) where m is the number of nodes between this node 824 * and <code>ancestor</code>, inclusive. Each <code>nextElement()</code> 825 * message is O(1).<P> 826 * 827 * Modifying the tree by inserting, removing, or moving a node invalidates 828 * any enumerations created before the modification. 829 * 830 * @see #isNodeAncestor 831 * @see #isNodeDescendant 832 * @exception IllegalArgumentException if <code>ancestor</code> is 833 * not an ancestor of this node 834 * @return an enumeration for following the path from an ancestor of 835 * this node to this one 836 */ 837 public Enumeration pathFromAncestorEnumeration(TreeNode ancestor) { 838 return new PathBetweenNodesEnumeration(ancestor, this); 839 } 840 841 842 // 843 // Child Queries 844 // 845 846 /** 847 * Returns true if <code>aNode</code> is a child of this node. If 848 * <code>aNode</code> is null, this method returns false. 849 * 850 * @return true if <code>aNode</code> is a child of this node; false if 851 * <code>aNode</code> is null 852 */ 853 public boolean isNodeChild(TreeNode aNode) { 854 boolean retval; 855 856 if (aNode == null) { 857 retval = false; 858 } else { 859 if (getChildCount() == 0) { 860 retval = false; 861 } else { 862 retval = (aNode.getParent() == this); 863 } 864 } 865 866 return retval; 867 } 868 869 870 /** 871 * Returns this node's first child. If this node has no children, 872 * throws NoSuchElementException. 873 * 874 * @return the first child of this node 875 * @exception NoSuchElementException if this node has no children 876 */ 877 public TreeNode getFirstChild() { 878 if (getChildCount() == 0) { 879 throw new NoSuchElementException("node has no children"); 880 } 881 return getChildAt(0); 882 } 883 884 885 /** 886 * Returns this node's last child. If this node has no children, 887 * throws NoSuchElementException. 888 * 889 * @return the last child of this node 890 * @exception NoSuchElementException if this node has no children 891 */ 892 public TreeNode getLastChild() { 893 if (getChildCount() == 0) { 894 throw new NoSuchElementException("node has no children"); 895 } 896 return getChildAt(getChildCount()-1); 897 } 898 899 900 /** 901 * Returns the child in this node's child array that immediately 902 * follows <code>aChild</code>, which must be a child of this node. If 903 * <code>aChild</code> is the last child, returns null. This method 904 * performs a linear search of this node's children for 905 * <code>aChild</code> and is O(n) where n is the number of children; to 906 * traverse the entire array of children, use an enumeration instead. 907 * 908 * @see #children 909 * @exception IllegalArgumentException if <code>aChild</code> is 910 * null or is not a child of this node 911 * @return the child of this node that immediately follows 912 * <code>aChild</code> 913 */ 914 public TreeNode getChildAfter(TreeNode aChild) { 915 if (aChild == null) { 916 throw new IllegalArgumentException("argument is null"); 917 } 918 919 int index = getIndex(aChild); // linear search 920 921 if (index == -1) { 922 throw new IllegalArgumentException("node is not a child"); 923 } 924 925 if (index < getChildCount() - 1) { 926 return getChildAt(index + 1); 927 } else { 928 return null; 929 } 930 } 931 932 933 /** 934 * Returns the child in this node's child array that immediately 935 * precedes <code>aChild</code>, which must be a child of this node. If 936 * <code>aChild</code> is the first child, returns null. This method 937 * performs a linear search of this node's children for <code>aChild</code> 938 * and is O(n) where n is the number of children. 939 * 940 * @exception IllegalArgumentException if <code>aChild</code> is null 941 * or is not a child of this node 942 * @return the child of this node that immediately precedes 943 * <code>aChild</code> 944 */ 945 public TreeNode getChildBefore(TreeNode aChild) { 946 if (aChild == null) { 947 throw new IllegalArgumentException("argument is null"); 948 } 949 950 int index = getIndex(aChild); // linear search 951 952 if (index == -1) { 953 throw new IllegalArgumentException("argument is not a child"); 954 } 955 956 if (index > 0) { 957 return getChildAt(index - 1); 958 } else { 959 return null; 960 } 961 } 962 963 964 // 965 // Sibling Queries 966 // 967 968 969 /** 970 * Returns true if <code>anotherNode</code> is a sibling of (has the 971 * same parent as) this node. A node is its own sibling. If 972 * <code>anotherNode</code> is null, returns false. 973 * 974 * @param anotherNode node to test as sibling of this node 975 * @return true if <code>anotherNode</code> is a sibling of this node 976 */ 977 public boolean isNodeSibling(TreeNode anotherNode) { 978 boolean retval; 979 980 if (anotherNode == null) { 981 retval = false; 982 } else if (anotherNode == this) { 983 retval = true; 984 } else { 985 TreeNode myParent = getParent(); 986 retval = (myParent != null && myParent == anotherNode.getParent()); 987 988 if (retval && !((DefaultMutableTreeNode)getParent()) 989 .isNodeChild(anotherNode)) { 990 throw new Error("sibling has different parent"); 991 } 992 } 993 994 return retval; 995 } 996 997 998 /** 999 * Returns the number of siblings of this node. A node is its own sibling 1000 * (if it has no parent or no siblings, this method returns 1001 * <code>1</code>). 1002 * 1003 * @return the number of siblings of this node 1004 */ 1005 public int getSiblingCount() { 1006 TreeNode myParent = getParent(); 1007 1008 if (myParent == null) { 1009 return 1; 1010 } else { 1011 return myParent.getChildCount(); 1012 } 1013 } 1014 1015 1016 /** 1017 * Returns the next sibling of this node in the parent's children array. 1018 * Returns null if this node has no parent or is the parent's last child. 1019 * This method performs a linear search that is O(n) where n is the number 1020 * of children; to traverse the entire array, use the parent's child 1021 * enumeration instead. 1022 * 1023 * @see #children 1024 * @return the sibling of this node that immediately follows this node 1025 */ 1026 public DefaultMutableTreeNode getNextSibling() { 1027 DefaultMutableTreeNode retval; 1028 1029 DefaultMutableTreeNode myParent = (DefaultMutableTreeNode)getParent(); 1030 1031 if (myParent == null) { 1032 retval = null; 1033 } else { 1034 retval = (DefaultMutableTreeNode)myParent.getChildAfter(this); // linear search 1035 } 1036 1037 if (retval != null && !isNodeSibling(retval)) { 1038 throw new Error("child of parent is not a sibling"); 1039 } 1040 1041 return retval; 1042 } 1043 1044 1045 /** 1046 * Returns the previous sibling of this node in the parent's children 1047 * array. Returns null if this node has no parent or is the parent's 1048 * first child. This method performs a linear search that is O(n) where n 1049 * is the number of children. 1050 * 1051 * @return the sibling of this node that immediately precedes this node 1052 */ 1053 public DefaultMutableTreeNode getPreviousSibling() { 1054 DefaultMutableTreeNode retval; 1055 1056 DefaultMutableTreeNode myParent = (DefaultMutableTreeNode)getParent(); 1057 1058 if (myParent == null) { 1059 retval = null; 1060 } else { 1061 retval = (DefaultMutableTreeNode)myParent.getChildBefore(this); // linear search 1062 } 1063 1064 if (retval != null && !isNodeSibling(retval)) { 1065 throw new Error("child of parent is not a sibling"); 1066 } 1067 1068 return retval; 1069 } 1070 1071 1072 1073 // 1074 // Leaf Queries 1075 // 1076 1077 /** 1078 * Returns true if this node has no children. To distinguish between 1079 * nodes that have no children and nodes that <i>cannot</i> have 1080 * children (e.g. to distinguish files from empty directories), use this 1081 * method in conjunction with <code>getAllowsChildren</code> 1082 * 1083 * @see #getAllowsChildren 1084 * @return true if this node has no children 1085 */ 1086 public boolean isLeaf() { 1087 return (getChildCount() == 0); 1088 } 1089 1090 1091 /** 1092 * Finds and returns the first leaf that is a descendant of this node -- 1093 * either this node or its first child's first leaf. 1094 * Returns this node if it is a leaf. 1095 * 1096 * @see #isLeaf 1097 * @see #isNodeDescendant 1098 * @return the first leaf in the subtree rooted at this node 1099 */ 1100 public DefaultMutableTreeNode getFirstLeaf() { 1101 DefaultMutableTreeNode node = this; 1102 1103 while (!node.isLeaf()) { 1104 node = (DefaultMutableTreeNode)node.getFirstChild(); 1105 } 1106 1107 return node; 1108 } 1109 1110 1111 /** 1112 * Finds and returns the last leaf that is a descendant of this node -- 1113 * either this node or its last child's last leaf. 1114 * Returns this node if it is a leaf. 1115 * 1116 * @see #isLeaf 1117 * @see #isNodeDescendant 1118 * @return the last leaf in the subtree rooted at this node 1119 */ 1120 public DefaultMutableTreeNode getLastLeaf() { 1121 DefaultMutableTreeNode node = this; 1122 1123 while (!node.isLeaf()) { 1124 node = (DefaultMutableTreeNode)node.getLastChild(); 1125 } 1126 1127 return node; 1128 } 1129 1130 1131 /** 1132 * Returns the leaf after this node or null if this node is the 1133 * last leaf in the tree. 1134 * <p> 1135 * In this implementation of the <code>MutableNode</code> interface, 1136 * this operation is very inefficient. In order to determine the 1137 * next node, this method first performs a linear search in the 1138 * parent's child-list in order to find the current node. 1139 * <p> 1140 * That implementation makes the operation suitable for short 1141 * traversals from a known position. But to traverse all of the 1142 * leaves in the tree, you should use <code>depthFirstEnumeration</code> 1143 * to enumerate the nodes in the tree and use <code>isLeaf</code> 1144 * on each node to determine which are leaves. 1145 * 1146 * @see #depthFirstEnumeration 1147 * @see #isLeaf 1148 * @return returns the next leaf past this node 1149 */ 1150 public DefaultMutableTreeNode getNextLeaf() { 1151 DefaultMutableTreeNode nextSibling; 1152 DefaultMutableTreeNode myParent = (DefaultMutableTreeNode)getParent(); 1153 1154 if (myParent == null) 1155 return null; 1156 1157 nextSibling = getNextSibling(); // linear search 1158 1159 if (nextSibling != null) 1160 return nextSibling.getFirstLeaf(); 1161 1162 return myParent.getNextLeaf(); // tail recursion 1163 } 1164 1165 1166 /** 1167 * Returns the leaf before this node or null if this node is the 1168 * first leaf in the tree. 1169 * <p> 1170 * In this implementation of the <code>MutableNode</code> interface, 1171 * this operation is very inefficient. In order to determine the 1172 * previous node, this method first performs a linear search in the 1173 * parent's child-list in order to find the current node. 1174 * <p> 1175 * That implementation makes the operation suitable for short 1176 * traversals from a known position. But to traverse all of the 1177 * leaves in the tree, you should use <code>depthFirstEnumeration</code> 1178 * to enumerate the nodes in the tree and use <code>isLeaf</code> 1179 * on each node to determine which are leaves. 1180 * 1181 * @see #depthFirstEnumeration 1182 * @see #isLeaf 1183 * @return returns the leaf before this node 1184 */ 1185 public DefaultMutableTreeNode getPreviousLeaf() { 1186 DefaultMutableTreeNode previousSibling; 1187 DefaultMutableTreeNode myParent = (DefaultMutableTreeNode)getParent(); 1188 1189 if (myParent == null) 1190 return null; 1191 1192 previousSibling = getPreviousSibling(); // linear search 1193 1194 if (previousSibling != null) 1195 return previousSibling.getLastLeaf(); 1196 1197 return myParent.getPreviousLeaf(); // tail recursion 1198 } 1199 1200 1201 /** 1202 * Returns the total number of leaves that are descendants of this node. 1203 * If this node is a leaf, returns <code>1</code>. This method is O(n) 1204 * where n is the number of descendants of this node. 1205 * 1206 * @see #isNodeAncestor 1207 * @return the number of leaves beneath this node 1208 */ 1209 public int getLeafCount() { 1210 int count = 0; 1211 1212 TreeNode node; 1213 Enumeration enum_ = breadthFirstEnumeration(); // order matters not 1214 1215 while (enum_.hasMoreElements()) { 1216 node = (TreeNode)enum_.nextElement(); 1217 if (node.isLeaf()) { 1218 count++; 1219 } 1220 } 1221 1222 if (count < 1) { 1223 throw new Error("tree has zero leaves"); 1224 } 1225 1226 return count; 1227 } 1228 1229 1230 // 1231 // Overrides 1232 // 1233 1234 /** 1235 * Returns the result of sending <code>toString()</code> to this node's 1236 * user object, or the empty string if the node has no user object. 1237 * 1238 * @see #getUserObject 1239 */ 1240 public String toString() { 1241 if (userObject == null) { 1242 return ""; 1243 } else { 1244 return userObject.toString(); 1245 } 1246 } 1247 1248 /** 1249 * Overridden to make clone public. Returns a shallow copy of this node; 1250 * the new node has no parent or children and has a reference to the same 1251 * user object, if any. 1252 * 1253 * @return a copy of this node 1254 */ 1255 public Object clone() { 1256 DefaultMutableTreeNode newNode; 1257 1258 try { 1259 newNode = (DefaultMutableTreeNode)super.clone(); 1260 1261 // shallow copy -- the new node has no parent or children 1262 newNode.children = null; 1263 newNode.parent = null; 1264 1265 } catch (CloneNotSupportedException e) { 1266 // Won't happen because we implement Cloneable 1267 throw new Error(e.toString()); 1268 } 1269 1270 return newNode; 1271 } 1272 1273 1274 // Serialization support. 1275 private void writeObject(ObjectOutputStream s) throws IOException { 1276 Object[] tValues; 1277 1278 s.defaultWriteObject(); 1279 // Save the userObject, if its Serializable. 1280 if(userObject != null && userObject instanceof Serializable) { 1281 tValues = new Object[2]; 1282 tValues[0] = "userObject"; 1283 tValues[1] = userObject; 1284 } 1285 else 1286 tValues = new Object[0]; 1287 s.writeObject(tValues); 1288 } 1289 1290 private void readObject(ObjectInputStream s) 1291 throws IOException, ClassNotFoundException { 1292 Object[] tValues; 1293 1294 s.defaultReadObject(); 1295 1296 tValues = (Object[])s.readObject(); 1297 1298 if(tValues.length > 0 && tValues[0].equals("userObject")) 1299 userObject = tValues[1]; 1300 } 1301 1302 private final class PreorderEnumeration implements Enumeration<TreeNode> { 1303 private final Stack<Enumeration> stack = new Stack<Enumeration>(); 1304 1305 public PreorderEnumeration(TreeNode rootNode) { 1306 super(); 1307 Vector<TreeNode> v = new Vector<TreeNode>(1); 1308 v.addElement(rootNode); // PENDING: don't really need a vector 1309 stack.push(v.elements()); 1310 } 1311 1312 public boolean hasMoreElements() { 1313 return (!stack.empty() && stack.peek().hasMoreElements()); 1314 } 1315 1316 public TreeNode nextElement() { 1317 Enumeration enumer = stack.peek(); 1318 TreeNode node = (TreeNode)enumer.nextElement(); 1319 Enumeration children = node.children(); 1320 1321 if (!enumer.hasMoreElements()) { 1322 stack.pop(); 1323 } 1324 if (children.hasMoreElements()) { 1325 stack.push(children); 1326 } 1327 return node; 1328 } 1329 1330 } // End of class PreorderEnumeration 1331 1332 1333 1334 final class PostorderEnumeration implements Enumeration<TreeNode> { 1335 protected TreeNode root; 1336 protected Enumeration<TreeNode> children; 1337 protected Enumeration<TreeNode> subtree; 1338 1339 public PostorderEnumeration(TreeNode rootNode) { 1340 super(); 1341 root = rootNode; 1342 children = root.children(); 1343 subtree = EMPTY_ENUMERATION; 1344 } 1345 1346 public boolean hasMoreElements() { 1347 return root != null; 1348 } 1349 1350 public TreeNode nextElement() { 1351 TreeNode retval; 1352 1353 if (subtree.hasMoreElements()) { 1354 retval = subtree.nextElement(); 1355 } else if (children.hasMoreElements()) { 1356 subtree = new PostorderEnumeration(children.nextElement()); 1357 retval = subtree.nextElement(); 1358 } else { 1359 retval = root; 1360 root = null; 1361 } 1362 1363 return retval; 1364 } 1365 1366 } // End of class PostorderEnumeration 1367 1368 1369 1370 final class BreadthFirstEnumeration implements Enumeration<TreeNode> { 1371 protected Queue queue; 1372 1373 public BreadthFirstEnumeration(TreeNode rootNode) { 1374 super(); 1375 Vector<TreeNode> v = new Vector<TreeNode>(1); 1376 v.addElement(rootNode); // PENDING: don't really need a vector 1377 queue = new Queue(); 1378 queue.enqueue(v.elements()); 1379 } 1380 1381 public boolean hasMoreElements() { 1382 return (!queue.isEmpty() && 1383 ((Enumeration)queue.firstObject()).hasMoreElements()); 1384 } 1385 1386 public TreeNode nextElement() { 1387 Enumeration enumer = (Enumeration)queue.firstObject(); 1388 TreeNode node = (TreeNode)enumer.nextElement(); 1389 Enumeration children = node.children(); 1390 1391 if (!enumer.hasMoreElements()) { 1392 queue.dequeue(); 1393 } 1394 if (children.hasMoreElements()) { 1395 queue.enqueue(children); 1396 } 1397 return node; 1398 } 1399 1400 1401 // A simple queue with a linked list data structure. 1402 final class Queue { 1403 QNode head; // null if empty 1404 QNode tail; 1405 1406 final class QNode { 1407 public Object object; 1408 public QNode next; // null if end 1409 public QNode(Object object, QNode next) { 1410 this.object = object; 1411 this.next = next; 1412 } 1413 } 1414 1415 public void enqueue(Object anObject) { 1416 if (head == null) { 1417 head = tail = new QNode(anObject, null); 1418 } else { 1419 tail.next = new QNode(anObject, null); 1420 tail = tail.next; 1421 } 1422 } 1423 1424 public Object dequeue() { 1425 if (head == null) { 1426 throw new NoSuchElementException("No more elements"); 1427 } 1428 1429 Object retval = head.object; 1430 QNode oldHead = head; 1431 head = head.next; 1432 if (head == null) { 1433 tail = null; 1434 } else { 1435 oldHead.next = null; 1436 } 1437 return retval; 1438 } 1439 1440 public Object firstObject() { 1441 if (head == null) { 1442 throw new NoSuchElementException("No more elements"); 1443 } 1444 1445 return head.object; 1446 } 1447 1448 public boolean isEmpty() { 1449 return head == null; 1450 } 1451 1452 } // End of class Queue 1453 1454 } // End of class BreadthFirstEnumeration 1455 1456 1457 1458 final class PathBetweenNodesEnumeration implements Enumeration<TreeNode> { 1459 protected Stack<TreeNode> stack; 1460 1461 public PathBetweenNodesEnumeration(TreeNode ancestor, 1462 TreeNode descendant) 1463 { 1464 super(); 1465 1466 if (ancestor == null || descendant == null) { 1467 throw new IllegalArgumentException("argument is null"); 1468 } 1469 1470 TreeNode current; 1471 1472 stack = new Stack<TreeNode>(); 1473 stack.push(descendant); 1474 1475 current = descendant; 1476 while (current != ancestor) { 1477 current = current.getParent(); 1478 if (current == null && descendant != ancestor) { 1479 throw new IllegalArgumentException("node " + ancestor + 1480 " is not an ancestor of " + descendant); 1481 } 1482 stack.push(current); 1483 } 1484 } 1485 1486 public boolean hasMoreElements() { 1487 return stack.size() > 0; 1488 } 1489 1490 public TreeNode nextElement() { 1491 try { 1492 return stack.pop(); 1493 } catch (EmptyStackException e) { 1494 throw new NoSuchElementException("No more elements"); 1495 } 1496 } 1497 1498 } // End of class PathBetweenNodesEnumeration 1499 1500 1501 1502 } // End of class DefaultMutableTreeNode