1. /*
  2. * @(#)DefaultMutableTreeNode.java 1.15 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.tree;
  11. // ISSUE: this class depends on nothing in AWT -- move to java.util?
  12. import java.io.*;
  13. import java.util.*;
  14. /**
  15. * A <code>DefaultMutableTreeNode</code> is a general-purpose node in a tree data
  16. * structure.
  17. * For examples of using default mutable tree nodes, see
  18. * <a
  19. href="http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html">How to Use Trees</a>
  20. * in <em>The Java Tutorial.</em>
  21. *
  22. * <p>
  23. *
  24. * A tree node may have at most one parent and 0 or more children.
  25. * <code>DefaultMutableTreeNode</code> provides operations for examining and modifying a
  26. * node's parent and children and also operations for examining the tree that
  27. * the node is a part of. A node's tree is the set of all nodes that can be
  28. * reached by starting at the node and following all the possible links to
  29. * parents and children. A node with no parent is the root of its tree; a
  30. * node with no children is a leaf. A tree may consist of many subtrees,
  31. * each node acting as the root for its own subtree.
  32. * <p>
  33. * This class provides enumerations for efficiently traversing a tree or
  34. * subtree in various orders or for following the path between two nodes.
  35. * A <code>DefaultMutableTreeNode</code> may also hold a reference to a user object, the
  36. * use of which is left to the user. Asking a <code>DefaultMutableTreeNode</code> for its
  37. * string representation with <code>toString()</code> returns the string
  38. * representation of its user object.
  39. * <p>
  40. * <b>This is not a thread safe class.</b>If you intend to use
  41. * a DefaultMutableTreeNode (or a tree of TreeNodes) in more than one thread, you
  42. * need to do your own synchronizing. A good convention to adopt is
  43. * synchronizing on the root node of a tree.
  44. * <p>
  45. * While DefaultMutableTreeNode implements the MutableTreeNode interface and
  46. * will allow you to add in any implementation of MutableTreeNode not all
  47. * of the methods in DefaultMutableTreeNode will be applicable to all
  48. * MutableTreeNodes implementations. Especially with some of the enumerations
  49. * that are provided, using some of these methods assumes the
  50. * DefaultMutableTreeNode contains only DefaultMutableNode instances. All
  51. * of the TreeNode/MutableTreeNode methods will behave as defined no
  52. * matter what implementations are added.
  53. *
  54. * <p>
  55. * <strong>Warning:</strong>
  56. * Serialized objects of this class will not be compatible with
  57. * future Swing releases. The current serialization support is appropriate
  58. * for short term storage or RMI between applications running the same
  59. * version of Swing. A future release of Swing will provide support for
  60. * long term persistence.
  61. *
  62. * @see MutableTreeNode
  63. *
  64. * @version 1.15 02/02/00
  65. * @author Rob Davis
  66. */
  67. public class DefaultMutableTreeNode extends Object implements Cloneable,
  68. MutableTreeNode, Serializable
  69. {
  70. /**
  71. * An enumeration that is always empty. This is used when an enumeration
  72. * of a leaf node's children is requested.
  73. */
  74. static public final Enumeration EMPTY_ENUMERATION
  75. = new Enumeration() {
  76. public boolean hasMoreElements() { return false; }
  77. public Object nextElement() {
  78. throw new NoSuchElementException("No more elements");
  79. }
  80. };
  81. /** this node's parent, or null if this node has no parent */
  82. protected MutableTreeNode parent;
  83. /** array of children, may be null if this node has no children */
  84. protected Vector children;
  85. /** optional user object */
  86. transient protected Object userObject;
  87. /** true if the node is able to have children */
  88. protected boolean allowsChildren;
  89. /**
  90. * Creates a tree node that has no parent and no children, but which
  91. * allows children.
  92. */
  93. public DefaultMutableTreeNode() {
  94. this(null);
  95. }
  96. /**
  97. * Creates a tree node with no parent, no children, but which allows
  98. * children, and initializes it with the specified user object.
  99. *
  100. * @param userObject an Object provided by the user that constitutes
  101. * the node's data
  102. */
  103. public DefaultMutableTreeNode(Object userObject) {
  104. this(userObject, true);
  105. }
  106. /**
  107. * Creates a tree node with no parent, no children, initialized with
  108. * the specified user object, and that allows children only if
  109. * specified.
  110. *
  111. * @param userObject an Object provided by the user that constitutes
  112. * the node's data
  113. * @param allowsChildren if true, the node is allowed to have child
  114. * nodes -- otherwise, it is always a leaf node
  115. */
  116. public DefaultMutableTreeNode(Object userObject, boolean allowsChildren) {
  117. super();
  118. parent = null;
  119. this.allowsChildren = allowsChildren;
  120. this.userObject = userObject;
  121. }
  122. //
  123. // Primitives
  124. //
  125. /**
  126. * Removes <code>newChild</code> from its present parent (if it has a
  127. * parent), sets the child's parent to this node, and then adds the child
  128. * to this node's child array at index <code>childIndex</code>.
  129. * <code>newChild</code> must not be null and must not be an ancestor of
  130. * this node.
  131. *
  132. * @param newChild the MutableTreeNode to insert under this node
  133. * @param childIndex the index in this node's child array
  134. * where this node is to be inserted
  135. * @exception ArrayIndexOutOfBoundsException if
  136. * <code>childIndex</code> is out of bounds
  137. * @exception IllegalArgumentException if
  138. * <code>newChild</code> is null or is an
  139. * ancestor of this node
  140. * @exception IllegalStateException if this node does not allow
  141. * children
  142. * @see #isNodeDescendant
  143. */
  144. public void insert(MutableTreeNode newChild, int childIndex) {
  145. if (!allowsChildren) {
  146. throw new IllegalStateException("node does not allow children");
  147. } else if (newChild == null) {
  148. throw new IllegalArgumentException("new child is null");
  149. } else if (isNodeAncestor(newChild)) {
  150. throw new IllegalArgumentException("new child is an ancestor");
  151. }
  152. MutableTreeNode oldParent = (MutableTreeNode)newChild.getParent();
  153. if (oldParent != null) {
  154. oldParent.remove(newChild);
  155. }
  156. newChild.setParent(this);
  157. if (children == null) {
  158. children = new Vector();
  159. }
  160. children.insertElementAt(newChild, childIndex);
  161. }
  162. /**
  163. * Removes the child at the specified index from this node's children
  164. * and sets that node's parent to null. The child node to remove
  165. * must be a <code>MutableTreeNode</code>.
  166. *
  167. * @param childIndex the index in this node's child array
  168. * of the child to remove
  169. * @exception ArrayIndexOutOfBoundsException if
  170. * <code>childIndex</code> is out of bounds
  171. */
  172. public void remove(int childIndex) {
  173. MutableTreeNode child = (MutableTreeNode)getChildAt(childIndex);
  174. children.removeElementAt(childIndex);
  175. child.setParent(null);
  176. }
  177. /**
  178. * Sets this node's parent to <code>newParent</code> but does not
  179. * change the parent's child array. This method is called from
  180. * <code>insert()</code> and <code>remove()</code> to
  181. * reassign a child's parent, it should not be messaged from anywhere
  182. * else.
  183. *
  184. * @param newParent this node's new parent
  185. */
  186. public void setParent(MutableTreeNode newParent) {
  187. parent = newParent;
  188. }
  189. /**
  190. * Returns this node's parent or null if this node has no parent.
  191. *
  192. * @return this node's parent TreeNode, or null if this node has no parent
  193. */
  194. public TreeNode getParent() {
  195. return parent;
  196. }
  197. /**
  198. * Returns the child at the specified index in this node's child array.
  199. *
  200. * @param index an index into this node's child array
  201. * @exception ArrayIndexOutOfBoundsException if <code>index</code>
  202. * is out of bounds
  203. * @return the TreeNode in this node's child array at the specified index
  204. */
  205. public TreeNode getChildAt(int index) {
  206. if (children == null) {
  207. throw new ArrayIndexOutOfBoundsException("node has no children");
  208. }
  209. return (TreeNode)children.elementAt(index);
  210. }
  211. /**
  212. * Returns the number of children of this node.
  213. *
  214. * @return an int giving the number of children of this node
  215. */
  216. public int getChildCount() {
  217. if (children == null) {
  218. return 0;
  219. } else {
  220. return children.size();
  221. }
  222. }
  223. /**
  224. * Returns the index of the specified child in this node's child array.
  225. * If the specified node is not a child of this node, returns
  226. * <code>-1</code>. This method performs a linear search and is O(n)
  227. * where n is the number of children.
  228. *
  229. * @param aChild the TreeNode to search for among this node's children
  230. * @exception IllegalArgumentException if <code>aChild</code>
  231. * is null
  232. * @return an int giving the index of the node in this node's child
  233. * array, or <code>-1</code> if the specified node is a not
  234. * a child of this node
  235. */
  236. public int getIndex(TreeNode aChild) {
  237. if (aChild == null) {
  238. throw new IllegalArgumentException("argument is null");
  239. }
  240. if (!isNodeChild(aChild)) {
  241. return -1;
  242. }
  243. return children.indexOf(aChild); // linear search
  244. }
  245. /**
  246. * Creates and returns a forward-order enumeration of this node's
  247. * children. Modifying this node's child array invalidates any child
  248. * enumerations created before the modification.
  249. *
  250. * @return an Enumeration of this node's children
  251. */
  252. public Enumeration children() {
  253. if (children == null) {
  254. return EMPTY_ENUMERATION;
  255. } else {
  256. return children.elements();
  257. }
  258. }
  259. /**
  260. * Determines whether or not this node is allowed to have children.
  261. * If <code>allows</code> is false, all of this node's children are
  262. * removed.
  263. * <p>
  264. * Note: By default, a node allows children.
  265. *
  266. * @param allows true if this node is allowed to have children
  267. */
  268. public void setAllowsChildren(boolean allows) {
  269. if (allows != allowsChildren) {
  270. allowsChildren = allows;
  271. if (!allowsChildren) {
  272. removeAllChildren();
  273. }
  274. }
  275. }
  276. /**
  277. * Returns true if this node is allowed to have children.
  278. *
  279. * @return true if this node allows children, else false
  280. */
  281. public boolean getAllowsChildren() {
  282. return allowsChildren;
  283. }
  284. /**
  285. * Sets the user object for this node to <code>userObject</code>.
  286. *
  287. * @param userObject the Object that constitutes this node's
  288. * user-specified data
  289. * @see #getUserObject
  290. * @see #toString
  291. */
  292. public void setUserObject(Object userObject) {
  293. this.userObject = userObject;
  294. }
  295. /**
  296. * Returns this node's user object.
  297. *
  298. * @return the Object stored at this node by the user
  299. * @see #setUserObject
  300. * @see #toString
  301. */
  302. public Object getUserObject() {
  303. return userObject;
  304. }
  305. //
  306. // Derived methods
  307. //
  308. /**
  309. * Removes the subtree rooted at this node from the tree, giving this
  310. * node a null parent. Does nothing if this node is the root of its
  311. * tree.
  312. */
  313. public void removeFromParent() {
  314. MutableTreeNode parent = (MutableTreeNode)getParent();
  315. if (parent != null) {
  316. parent.remove(this);
  317. }
  318. }
  319. /**
  320. * Removes <code>aChild</code> from this node's child array, giving it a
  321. * null parent.
  322. *
  323. * @param aChild a child of this node to remove
  324. * @exception IllegalArgumentException if <code>aChild</code>
  325. * is null or is not a child of this node
  326. */
  327. public void remove(MutableTreeNode aChild) {
  328. if (aChild == null) {
  329. throw new IllegalArgumentException("argument is null");
  330. }
  331. if (!isNodeChild(aChild)) {
  332. throw new IllegalArgumentException("argument is not a child");
  333. }
  334. remove(getIndex(aChild)); // linear search
  335. }
  336. /**
  337. * Removes all of this node's children, setting their parents to null.
  338. * If this node has no children, this method does nothing.
  339. */
  340. public void removeAllChildren() {
  341. for (int i = getChildCount()-1; i >= 0; i--) {
  342. remove(i);
  343. }
  344. }
  345. /**
  346. * Removes <code>newChild</code> from its parent and makes it a child of
  347. * this node by adding it to the end of this node's child array.
  348. *
  349. * @see #insert
  350. * @param newChild node to add as a child of this node
  351. * @exception IllegalArgumentException if <code>newChild</code>
  352. * is null
  353. * @exception IllegalStateException if this node does not allow
  354. * children
  355. */
  356. public void add(MutableTreeNode newChild) {
  357. if(newChild != null && newChild.getParent() == this)
  358. insert(newChild, getChildCount() - 1);
  359. else
  360. insert(newChild, getChildCount());
  361. }
  362. //
  363. // Tree Queries
  364. //
  365. /**
  366. * Returns true if <code>anotherNode</code> is an ancestor of this node
  367. * -- if it is this node, this node's parent, or an ancestor of this
  368. * node's parent. (Note that a node is considered an ancestor of itself.)
  369. * If <code>anotherNode</code> is null, this method returns false. This
  370. * operation is at worst O(h) where h is the distance from the root to
  371. * this node.
  372. *
  373. * @see #isNodeDescendant
  374. * @see #getSharedAncestor
  375. * @param anotherNode node to test as an ancestor of this node
  376. * @return true if this node is a descendant of <code>anotherNode</code>
  377. */
  378. public boolean isNodeAncestor(TreeNode anotherNode) {
  379. if (anotherNode == null) {
  380. return false;
  381. }
  382. TreeNode ancestor = this;
  383. do {
  384. if (ancestor == anotherNode) {
  385. return true;
  386. }
  387. } while((ancestor = ancestor.getParent()) != null);
  388. return false;
  389. }
  390. /**
  391. * Returns true if <code>anotherNode</code> is a descendant of this node
  392. * -- if it is this node, one of this node's children, or a descendant of
  393. * one of this node's children. Note that a node is considered a
  394. * descendant of itself. If <code>anotherNode</code> is null, returns
  395. * false. This operation is at worst O(h) where h is the distance from the
  396. * root to <code>anotherNode</code>.
  397. *
  398. * @see #isNodeAncestor
  399. * @see #getSharedAncestor
  400. * @param anotherNode node to test as descendant of this node
  401. * @return true if this node is an ancestor of <code>anotherNode</code>
  402. */
  403. public boolean isNodeDescendant(DefaultMutableTreeNode anotherNode) {
  404. if (anotherNode == null)
  405. return false;
  406. return anotherNode.isNodeAncestor(this);
  407. }
  408. /**
  409. * Returns the nearest common ancestor to this node and <code>aNode</code>.
  410. * Returns null, if no such ancestor exists -- if this node and
  411. * <code>aNode</code> are in different trees or if <code>aNode</code> is
  412. * null. A node is considered an ancestor of itself.
  413. *
  414. * @see #isNodeAncestor
  415. * @see #isNodeDescendant
  416. * @param aNode node to find common ancestor with
  417. * @return nearest ancestor common to this node and <code>aNode</code>,
  418. * or null if none
  419. */
  420. public TreeNode getSharedAncestor(DefaultMutableTreeNode aNode) {
  421. if (aNode == this) {
  422. return this;
  423. } else if (aNode == null) {
  424. return null;
  425. }
  426. int level1, level2, diff;
  427. TreeNode node1, node2;
  428. level1 = getLevel();
  429. level2 = aNode.getLevel();
  430. if (level2 > level1) {
  431. diff = level2 - level1;
  432. node1 = aNode;
  433. node2 = this;
  434. } else {
  435. diff = level1 - level2;
  436. node1 = this;
  437. node2 = aNode;
  438. }
  439. // Go up the tree until the nodes are at the same level
  440. while (diff > 0) {
  441. node1 = node1.getParent();
  442. diff--;
  443. }
  444. // Move up the tree until we find a common ancestor. Since we know
  445. // that both nodes are at the same level, we won't cross paths
  446. // unknowingly (if there is a common ancestor, both nodes hit it in
  447. // the same iteration).
  448. do {
  449. if (node1 == node2) {
  450. return node1;
  451. }
  452. node1 = node1.getParent();
  453. node2 = node2.getParent();
  454. } while (node1 != null);// only need to check one -- they're at the
  455. // same level so if one is null, the other is
  456. if (node1 != null || node2 != null) {
  457. throw new Error ("nodes should be null");
  458. }
  459. return null;
  460. }
  461. /**
  462. * Returns true if and only if <code>aNode</code> is in the same tree
  463. * as this node. Returns false if <code>aNode</code> is null.
  464. *
  465. * @see #getSharedAncestor
  466. * @see #getRoot
  467. * @return true if <code>aNode</code> is in the same tree as this node;
  468. * false if <code>aNode</code> is null
  469. */
  470. public boolean isNodeRelated(DefaultMutableTreeNode aNode) {
  471. return (aNode != null) && (getRoot() == aNode.getRoot());
  472. }
  473. /**
  474. * Returns the depth of the tree rooted at this node -- the longest
  475. * distance from this node to a leaf. If this node has no children,
  476. * returns 0. This operation is much more expensive than
  477. * <code>getLevel()</code> because it must effectively traverse the entire
  478. * tree rooted at this node.
  479. *
  480. * @see #getLevel
  481. * @return the depth of the tree whose root is this node
  482. */
  483. public int getDepth() {
  484. Object last = null;
  485. Enumeration enum = breadthFirstEnumeration();
  486. while (enum.hasMoreElements()) {
  487. last = enum.nextElement();
  488. }
  489. if (last == null) {
  490. throw new Error ("nodes should be null");
  491. }
  492. return ((DefaultMutableTreeNode)last).getLevel() - getLevel();
  493. }
  494. /**
  495. * Returns the number of levels above this node -- the distance from
  496. * the root to this node. If this node is the root, returns 0.
  497. *
  498. * @see #getDepth
  499. * @return the number of levels above this node
  500. */
  501. public int getLevel() {
  502. TreeNode ancestor;
  503. int levels = 0;
  504. ancestor = this;
  505. while((ancestor = ancestor.getParent()) != null){
  506. levels++;
  507. }
  508. return levels;
  509. }
  510. /**
  511. * Returns the path from the root, to get to this node. The last
  512. * element in the path is this node.
  513. *
  514. * @return an array of TreeNode objects giving the path, where the
  515. * first element in the path is the root and the last
  516. * element is this node.
  517. */
  518. public TreeNode[] getPath() {
  519. return getPathToRoot(this, 0);
  520. }
  521. /**
  522. * Builds the parents of node up to and including the root node,
  523. * where the original node is the last element in the returned array.
  524. * The length of the returned array gives the node's depth in the
  525. * tree.
  526. *
  527. * @param aNode the TreeNode to get the path for
  528. * @param depth an int giving the number of steps already taken towards
  529. * the root (on recursive calls), used to size the returned array
  530. * @return an array of TreeNodes giving the path from the root to the
  531. * specified node
  532. */
  533. protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) {
  534. TreeNode[] retNodes;
  535. /* Check for null, in case someone passed in a null node, or
  536. they passed in an element that isn't rooted at root. */
  537. if(aNode == null) {
  538. if(depth == 0)
  539. return null;
  540. else
  541. retNodes = new TreeNode[depth];
  542. }
  543. else {
  544. depth++;
  545. retNodes = getPathToRoot(aNode.getParent(), depth);
  546. retNodes[retNodes.length - depth] = aNode;
  547. }
  548. return retNodes;
  549. }
  550. /**
  551. * Returns the user object path, from the root, to get to this node.
  552. * If some of the TreeNodes in the path have null user objects, the
  553. * returned path will contain nulls.
  554. */
  555. public Object[] getUserObjectPath() {
  556. TreeNode[] realPath = getPath();
  557. Object[] retPath = new Object[realPath.length];
  558. for(int counter = 0; counter < realPath.length; counter++)
  559. retPath[counter] = ((DefaultMutableTreeNode)realPath[counter])
  560. .getUserObject();
  561. return retPath;
  562. }
  563. /**
  564. * Returns the root of the tree that contains this node. The root is
  565. * the ancestor with a null parent.
  566. *
  567. * @see #isNodeAncestor
  568. * @return the root of the tree that contains this node
  569. */
  570. public TreeNode getRoot() {
  571. TreeNode ancestor = this;
  572. TreeNode previous;
  573. do {
  574. previous = ancestor;
  575. ancestor = ancestor.getParent();
  576. } while (ancestor != null);
  577. return previous;
  578. }
  579. /**
  580. * Returns true if this node is the root of the tree. The root is
  581. * the only node in the tree with a null parent; every tree has exactly
  582. * one root.
  583. *
  584. * @return true if this node is the root of its tree
  585. */
  586. public boolean isRoot() {
  587. return getParent() == null;
  588. }
  589. /**
  590. * Returns the node that follows this node in a preorder traversal of this
  591. * node's tree. Returns null if this node is the last node of the
  592. * traversal. This is an inefficient way to traverse the entire tree; use
  593. * an enumeration, instead.
  594. *
  595. * @see #preorderEnumeration
  596. * @return the node that follows this node in a preorder traversal, or
  597. * null if this node is last
  598. */
  599. public DefaultMutableTreeNode getNextNode() {
  600. if (getChildCount() == 0) {
  601. // No children, so look for nextSibling
  602. DefaultMutableTreeNode nextSibling = getNextSibling();
  603. if (nextSibling == null) {
  604. DefaultMutableTreeNode aNode = (DefaultMutableTreeNode)getParent();
  605. do {
  606. if (aNode == null) {
  607. return null;
  608. }
  609. nextSibling = aNode.getNextSibling();
  610. if (nextSibling != null) {
  611. return nextSibling;
  612. }
  613. aNode = (DefaultMutableTreeNode)aNode.getParent();
  614. } while(true);
  615. } else {
  616. return nextSibling;
  617. }
  618. } else {
  619. return (DefaultMutableTreeNode)getChildAt(0);
  620. }
  621. }
  622. /**
  623. * Returns the node that precedes this node in a preorder traversal of
  624. * this node's tree. Returns null if this node is the first node of the
  625. * traveral -- the root of the tree. 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