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 */ DefaultMutableTreeNode()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 */ DefaultMutableTreeNode(Object userObject)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 */ DefaultMutableTreeNode(Object userObject, boolean allowsChildren)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 */ clone()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 */ toString()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 */ add(MutableTreeNode child)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 */ getParent()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 */ remove(int index)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 */ remove(MutableTreeNode node)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 */ writeObject(ObjectOutputStream stream)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 */ readObject(ObjectInputStream stream)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 */ insert(MutableTreeNode node, int index)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 */ getPath()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 children()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 */ setParent(MutableTreeNode node)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 */ getChildAt(int index)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 */ getChildCount()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 */ getIndex(TreeNode node)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 */ setAllowsChildren(boolean allowsChildren)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 */ getAllowsChildren()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 */ setUserObject(Object userObject)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 */ getUserObject()394 public Object getUserObject() 395 { 396 return userObject; 397 } 398 399 /** 400 * Removes this node from its parent. 401 */ removeFromParent()402 public void removeFromParent() 403 { 404 parent.remove(this); 405 parent = null; 406 } 407 408 /** 409 * Removes all child nodes from this node. 410 */ removeAllChildren()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 */ isNodeAncestor(TreeNode node)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 */ isNodeDescendant(DefaultMutableTreeNode node)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 */ getSharedAncestor(DefaultMutableTreeNode node)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 */ isNodeRelated(DefaultMutableTreeNode node)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 */ getDepth()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 */ getLevel()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 */ getPathToRoot(TreeNode node, int depth)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 */ getUserObjectPath()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 */ getRoot()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 */ isRoot()659 public boolean isRoot() 660 { 661 return parent == null; 662 } 663 664 /** 665 * getNextNode 666 * 667 * @return DefaultMutableTreeNode 668 */ getNextNode()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 */ getPreviousNode()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 preorderEnumeration()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 postorderEnumeration()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 breadthFirstEnumeration()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 depthFirstEnumeration()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 pathFromAncestorEnumeration(TreeNode node)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 */ isNodeChild(TreeNode node)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 */ getFirstChild()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 */ getLastChild()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 */ getChildAfter(TreeNode node)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 */ getChildBefore(TreeNode node)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 */ isNodeSibling(TreeNode node)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 */ getSiblingCount()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 */ getNextSibling()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 */ getPreviousSibling()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 */ isLeaf()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 */ getFirstLeaf()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 */ getLastLeaf()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 */ getNextLeaf()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 */ getPreviousLeaf()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 */ getLeafCount()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 BreadthFirstEnumeration(TreeNode node)1066 BreadthFirstEnumeration(TreeNode node) 1067 { 1068 queue.add(node); 1069 } 1070 hasMoreElements()1071 public boolean hasMoreElements() 1072 { 1073 return !queue.isEmpty(); 1074 } 1075 nextElement()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 PreorderEnumeration(TreeNode node)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 hasMoreElements()1112 public boolean hasMoreElements() 1113 { 1114 return next != null; 1115 } 1116 nextElement()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 traverse(Enumeration<TreeNode> children)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 PostorderEnumeration(TreeNode node)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 hasMoreElements()1179 public boolean hasMoreElements() 1180 { 1181 return !nodes.isEmpty(); 1182 } 1183 nextElement()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 traverse(Enumeration<TreeNode> children)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 } 1224