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