1 /* DefaultMutableTreeNode.java --
2 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.tree;
41 import gnu.java.util.EmptyEnumeration;
43 import java.io.IOException;
44 import java.io.ObjectInputStream;
45 import java.io.ObjectOutputStream;
46 import java.io.Serializable;
47 import java.util.ArrayList;
48 import java.util.Enumeration;
49 import java.util.LinkedList;
50 import java.util.NoSuchElementException;
51 import java.util.Stack;
52 import java.util.Vector;
56 * A default implementation of the {@link MutableTreeNode} interface.
58 * @author Andrew Selkirk
59 * @author Robert Schuster (robertschuster@fsfe.org)
61 public class DefaultMutableTreeNode
62 implements Cloneable, MutableTreeNode, Serializable
64 private static final long serialVersionUID = -4298474751201349152L;
67 * An empty enumeration, returned by {@link #children()} if a node has no
70 public static final Enumeration<TreeNode> EMPTY_ENUMERATION =
71 new EmptyEnumeration<TreeNode>();
74 * The parent of this node (possibly <code>null</code>).
76 protected MutableTreeNode parent;
79 * The child nodes for this node (may be empty).
81 protected Vector<MutableTreeNode> children = new Vector<MutableTreeNode>();
86 protected transient Object userObject;
91 protected boolean allowsChildren;
94 * Creates a <code>DefaultMutableTreeNode</code> object.
95 * This is equivalent to <code>DefaultMutableTreeNode(null, true)</code>.
97 public DefaultMutableTreeNode()
103 * Creates a <code>DefaultMutableTreeNode</code> object with the given
104 * user object attached to it. This is equivalent to
105 * <code>DefaultMutableTreeNode(userObject, true)</code>.
107 * @param userObject the user object (<code>null</code> permitted).
109 public DefaultMutableTreeNode(Object userObject)
111 this(userObject, true);
115 * Creates a <code>DefaultMutableTreeNode</code> object with the given
116 * user object attached to it.
118 * @param userObject the user object (<code>null</code> permitted).
119 * @param allowsChildren <code>true</code> if the code allows to add child
120 * nodes, <code>false</code> otherwise
122 public DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
124 this.userObject = userObject;
125 this.allowsChildren = allowsChildren;
129 * Returns a clone of the node. The clone contains a shallow copy of the
130 * user object, and does not copy the parent node or the child nodes.
132 * @return A clone of the node.
134 public Object clone()
136 return new DefaultMutableTreeNode(this.userObject, this.allowsChildren);
140 * Returns a string representation of the node. This implementation returns
141 * <code>getUserObject().toString()</code>, or <code>null</code> if there
144 * @return A string representation of the node (possibly <code>null</code>).
146 public String toString()
148 if (userObject == null)
151 return userObject.toString();
155 * Adds a new child node to this node and sets this node as the parent of
156 * the child node. The child node must not be an ancestor of this node.
157 * If the tree uses the {@link DefaultTreeModel}, you must subsequently
158 * call {@link DefaultTreeModel#reload(TreeNode)}.
160 * @param child the child node (<code>null</code> not permitted).
162 * @throws IllegalStateException if {@link #getAllowsChildren()} returns
163 * <code>false</code>.
164 * @throws IllegalArgumentException if {@link #isNodeAncestor} returns
166 * @throws IllegalArgumentException if <code>child</code> is
169 public void add(MutableTreeNode child)
171 if (! allowsChildren)
172 throw new IllegalStateException();
175 throw new IllegalArgumentException();
177 if (isNodeAncestor(child))
178 throw new IllegalArgumentException("Cannot add ancestor node.");
181 child.setParent(this);
185 * Returns the parent node of this node.
187 * @return The parent node (possibly <code>null</code>).
189 public TreeNode getParent()
195 * Removes the child with the given index from this node.
197 * @param index the index (in the range <code>0</code> to
198 * <code>getChildCount() - 1</code>).
200 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is outside
203 public void remove(int index)
205 MutableTreeNode child = children.remove(index);
206 child.setParent(null);
210 * Removes the given child from this node and sets its parent to
213 * @param node the child node (<code>null</code> not permitted).
215 * @throws IllegalArgumentException if <code>node</code> is not a child of
217 * @throws IllegalArgumentException if <code>node</code> is null.
219 public void remove(MutableTreeNode node)
222 throw new IllegalArgumentException("Null 'node' argument.");
223 if (node.getParent() != this)
224 throw new IllegalArgumentException(
225 "The given 'node' is not a child of this node.");
226 children.remove(node);
227 node.setParent(null);
233 * @param stream the output stream
235 * @exception IOException If an error occurs
237 private void writeObject(ObjectOutputStream stream)
240 // TODO: Implement me.
246 * @param stream the input stream
248 * @exception IOException If an error occurs
249 * @exception ClassNotFoundException TODO
251 private void readObject(ObjectInputStream stream)
252 throws IOException, ClassNotFoundException
254 // TODO: Implement me.
258 * Inserts given child node at the given index.
260 * @param node the child node (<code>null</code> not permitted).
261 * @param index the index.
263 * @throws IllegalArgumentException if <code>node</code> is
264 * </code>null</code>.
266 public void insert(MutableTreeNode node, int index)
268 if (! allowsChildren)
269 throw new IllegalStateException();
272 throw new IllegalArgumentException("Null 'node' argument.");
274 if (isNodeAncestor(node))
275 throw new IllegalArgumentException("Cannot insert ancestor node.");
277 children.insertElementAt(node, index);
281 * Returns a path to this node from the root.
283 * @return an array of tree nodes
285 public TreeNode[] getPath()
287 return getPathToRoot(this, 0);
291 * Returns an enumeration containing all children of this node.
292 * <code>EMPTY_ENUMERATION</code> is returned if this node has no children.
294 * @return an enumeration of tree nodes
296 @SuppressWarnings("unchecked") // Required for API compatibility
297 public Enumeration children()
299 if (children.size() == 0)
300 return EMPTY_ENUMERATION;
302 return children.elements();
306 * Set the parent node for this node.
308 * @param node the parent node
310 public void setParent(MutableTreeNode node)
316 * Returns the child node at a given index.
318 * @param index the index
320 * @return the child node
322 public TreeNode getChildAt(int index)
324 return children.elementAt(index);
328 * Returns the number of children of this node.
330 * @return the number of children
332 public int getChildCount()
334 return children.size();
338 * Returns the index of the specified child node, or -1 if the node is not
339 * in fact a child of this node.
341 * @param node the node (<code>null</code> not permitted).
343 * @return The index of the specified child node, or -1.
345 * @throws IllegalArgumentException if <code>node</code> is <code>null</code>.
347 public int getIndex(TreeNode node)
350 throw new IllegalArgumentException("Null 'node' argument.");
351 return children.indexOf(node);
355 * Sets the flag that controls whether or not this node allows the addition /
356 * insertion of child nodes. If the flag is set to <code>false</code>, any
357 * existing children are removed.
359 * @param allowsChildren the flag.
361 public void setAllowsChildren(boolean allowsChildren)
365 this.allowsChildren = allowsChildren;
373 public boolean getAllowsChildren()
375 return allowsChildren;
379 * Sets the user object for this node
381 * @param userObject the user object
383 public void setUserObject(Object userObject)
385 this.userObject = userObject;
389 * Returns the user object attached to this node. <code>null</code> is
390 * returned when no user object is set.
392 * @return the user object
394 public Object getUserObject()
400 * Removes this node from its parent.
402 public void removeFromParent()
409 * Removes all child nodes from this node.
411 public void removeAllChildren()
413 for (int i = getChildCount() - 1; i >= 0; i--)
418 * Returns <code>true</code> if <code>node</code> is an ancestor of this
419 * tree node, and <code>false</code> otherwise. An ancestor node is any of:
421 * <li>this tree node;</li>
422 * <li>the parent node (if there is one);</li>
423 * <li>any ancestor of the parent node;</li>
425 * If <code>node</code> is <code>null</code>, this method returns
426 * <code>false</code>.
428 * @param node the node (<code>null</code> permitted).
432 public boolean isNodeAncestor(TreeNode node)
437 TreeNode current = this;
439 while (current != null && current != node)
440 current = current.getParent();
442 return current == node;
446 * Returns <code>true</code> if <code>node</code> is a descendant of this
447 * tree node, and <code>false</code> otherwise. A descendant node is any of:
449 * <li>this tree node;</li>
450 * <li>the child nodes belonging to this tree node, if there are any;</li>
451 * <li>any descendants of the child nodes;</li>
453 * If <code>node</code> is <code>null</code>, this method returns
454 * <code>false</code>.
456 * @param node the node (<code>null</code> permitted).
460 public boolean isNodeDescendant(DefaultMutableTreeNode node)
465 TreeNode current = node;
467 while (current != null
469 current = current.getParent();
471 return current == this;
481 public TreeNode getSharedAncestor(DefaultMutableTreeNode node)
483 TreeNode current = this;
484 ArrayList<TreeNode> list = new ArrayList<TreeNode>();
486 while (current != null)
489 current = current.getParent();
494 while (current != null)
496 if (list.contains(current))
499 current = current.getParent();
512 public boolean isNodeRelated(DefaultMutableTreeNode node)
517 return node.getRoot() == getRoot();
525 public int getDepth()
527 if ((! allowsChildren)
528 || children.size() == 0)
531 Stack<Integer> stack = new Stack<Integer>();
532 stack.push(new Integer(0));
533 TreeNode node = getChildAt(0);
537 while (! stack.empty())
539 if (node.getChildCount() != 0)
541 node = node.getChildAt(0);
542 stack.push(new Integer(0));
555 node = node.getParent();
556 size = node.getChildCount();
557 index = stack.pop().intValue() + 1;
565 node = node.getChildAt(index);
566 stack.push(new Integer(index));
580 public int getLevel()
583 TreeNode current = this;
587 current = current.getParent();
590 while (current != null);
603 protected TreeNode[] getPathToRoot(TreeNode node, int depth)
610 return new TreeNode[depth];
613 TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
614 path[path.length - depth - 1] = node;
623 public Object[] getUserObjectPath()
625 TreeNode[] path = getPathToRoot(this, 0);
626 Object[] object = new Object[path.length];
628 for (int index = 0; index < path.length; ++index)
629 object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject();
635 * Returns the root node by iterating the parents of this node.
637 * @return the root node
639 public TreeNode getRoot()
641 TreeNode current = this;
642 TreeNode check = current.getParent();
644 while (check != null)
647 check = current.getParent();
654 * Tells whether this node is the root node or not.
656 * @return <code>true</code> if this is the root node,
657 * <code>false</code>otherwise
659 public boolean isRoot()
661 return parent == null;
667 * @return DefaultMutableTreeNode
669 public DefaultMutableTreeNode getNextNode()
671 // Return first child.
672 if (getChildCount() != 0)
673 return (DefaultMutableTreeNode) getChildAt(0);
675 // Return next sibling (if needed the sibling of some parent).
676 DefaultMutableTreeNode node = this;
677 DefaultMutableTreeNode sibling;
681 sibling = node.getNextSibling();
682 node = (DefaultMutableTreeNode) node.getParent();
684 while (sibling == null &&
694 * @return DefaultMutableTreeNode
696 public DefaultMutableTreeNode getPreviousNode()
698 // Return null if no parent.
702 DefaultMutableTreeNode sibling = getPreviousSibling();
704 // Return parent if no sibling.
706 return (DefaultMutableTreeNode) parent;
708 // Return last leaf of sibling.
709 if (sibling.getChildCount() != 0)
710 return sibling.getLastLeaf();
717 * preorderEnumeration
719 * @return Enumeration
721 @SuppressWarnings("unchecked") // Required for API compatibility
722 public Enumeration preorderEnumeration()
724 return new PreorderEnumeration(this);
728 * postorderEnumeration
730 * @return Enumeration
732 @SuppressWarnings("unchecked") // Required for API compatibility
733 public Enumeration postorderEnumeration()
735 return new PostorderEnumeration(this);
739 * breadthFirstEnumeration
741 * @return Enumeration
743 @SuppressWarnings("unchecked") // Required for API compatibility
744 public Enumeration breadthFirstEnumeration()
746 return new BreadthFirstEnumeration(this);
750 * depthFirstEnumeration
752 * @return Enumeration
754 @SuppressWarnings("unchecked") // Required for API compatibility
755 public Enumeration depthFirstEnumeration()
757 return postorderEnumeration();
761 * pathFromAncestorEnumeration
765 * @return Enumeration
767 @SuppressWarnings("unchecked") // Required for API compatibility
768 public Enumeration pathFromAncestorEnumeration(TreeNode node)
771 throw new IllegalArgumentException();
773 TreeNode parent = this;
774 Vector<TreeNode> nodes = new Vector<TreeNode>();
777 while (parent != node && parent != null)
779 parent = parent.getParent();
780 nodes.add(0, parent);
784 throw new IllegalArgumentException();
786 return nodes.elements();
790 * Returns <code>true</code> if <code>node</code> is a child of this tree
791 * node, and <code>false</code> otherwise. If <code>node</code> is
792 * <code>null</code>, this method returns <code>false</code>.
794 * @param node the node (<code>null</code> permitted).
798 public boolean isNodeChild(TreeNode node)
803 return node.getParent() == this;
807 * Returns the first child node belonging to this tree node.
809 * @return The first child node.
811 * @throws NoSuchElementException if this tree node has no children.
813 public TreeNode getFirstChild()
815 return children.firstElement();
819 * Returns the last child node belonging to this tree node.
821 * @return The last child node.
823 * @throws NoSuchElementException if this tree node has no children.
825 public TreeNode getLastChild()
827 return children.lastElement();
831 * Returns the next child after the specified <code>node</code>, or
832 * <code>null</code> if there is no child after the specified
835 * @param node a child of this node (<code>null</code> not permitted).
837 * @return The next child, or <code>null</code>.
839 * @throws IllegalArgumentException if <code>node</code> is not a child of
840 * this node, or is <code>null</code>.
842 public TreeNode getChildAfter(TreeNode node)
844 if (node == null || node.getParent() != this)
845 throw new IllegalArgumentException();
847 int index = getIndex(node) + 1;
849 if (index == getChildCount())
852 return getChildAt(index);
856 * Returns the previous child before the specified <code>node</code>, or
857 * <code>null</code> if there is no child before the specified
860 * @param node a child of this node (<code>null</code> not permitted).
862 * @return The previous child, or <code>null</code>.
864 * @throws IllegalArgumentException if <code>node</code> is not a child of
865 * this node, or is <code>null</code>.
867 public TreeNode getChildBefore(TreeNode node)
869 if (node == null || node.getParent() != this)
870 throw new IllegalArgumentException();
872 int index = getIndex(node) - 1;
877 return getChildAt(index);
881 * Returns <code>true</code> if this tree node and <code>node</code> share
882 * the same parent. If <code>node</code> is this tree node, the method
883 * returns <code>true</code> and if <code>node</code> is <code>null</code>
884 * this method returns <code>false</code>.
886 * @param node the node (<code>null</code> permitted).
890 public boolean isNodeSibling(TreeNode node)
896 return node.getParent() == getParent() && getParent() != null;
900 * Returns the number of siblings for this tree node. If the tree node has
901 * a parent, this method returns the child count for the parent, otherwise
902 * it returns <code>1</code>.
904 * @return The sibling count.
906 public int getSiblingCount()
911 return parent.getChildCount();
915 * Returns the next sibling for this tree node. If this node has no parent,
916 * or this node is the last child of its parent, this method returns
919 * @return The next sibling, or <code>null</code>.
921 public DefaultMutableTreeNode getNextSibling()
926 int index = parent.getIndex(this) + 1;
928 if (index == parent.getChildCount())
931 return (DefaultMutableTreeNode) parent.getChildAt(index);
935 * Returns the previous sibling for this tree node. If this node has no
936 * parent, or this node is the first child of its parent, this method returns
939 * @return The previous sibling, or <code>null</code>.
941 public DefaultMutableTreeNode getPreviousSibling()
946 int index = parent.getIndex(this) - 1;
951 return (DefaultMutableTreeNode) parent.getChildAt(index);
955 * Returns <code>true</code> if this tree node is a lead node (that is, it
956 * has no children), and <code>false</otherwise>.
960 public boolean isLeaf()
962 return children.size() == 0;
966 * Returns the first leaf node that is a descendant of this node. Recall
967 * that a node is its own descendant, so if this node has no children then
968 * it is returned as the first leaf.
970 * @return The first leaf node.
972 public DefaultMutableTreeNode getFirstLeaf()
974 TreeNode current = this;
976 while (current.getChildCount() > 0)
977 current = current.getChildAt(0);
979 return (DefaultMutableTreeNode) current;
983 * Returns the last leaf node that is a descendant of this node. Recall
984 * that a node is its own descendant, so if this node has no children then
985 * it is returned as the last leaf.
987 * @return The first leaf node.
989 public DefaultMutableTreeNode getLastLeaf()
991 TreeNode current = this;
992 int size = current.getChildCount();
996 current = current.getChildAt(size - 1);
997 size = current.getChildCount();
1000 return (DefaultMutableTreeNode) current;
1004 * Returns the next leaf node after this tree node.
1006 * @return The next leaf node, or <code>null</code>.
1008 public DefaultMutableTreeNode getNextLeaf()
1010 // if there is a next sibling, return its first leaf
1011 DefaultMutableTreeNode sibling = getNextSibling();
1012 if (sibling != null)
1013 return sibling.getFirstLeaf();
1014 // otherwise move up one level and try again...
1016 return ((DefaultMutableTreeNode) parent).getNextLeaf();
1021 * Returns the previous leaf node before this tree node.
1023 * @return The previous leaf node, or <code>null</code>.
1025 public DefaultMutableTreeNode getPreviousLeaf()
1027 // if there is a previous sibling, return its last leaf
1028 DefaultMutableTreeNode sibling = getPreviousSibling();
1029 if (sibling != null)
1030 return sibling.getLastLeaf();
1031 // otherwise move up one level and try again...
1033 return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
1042 public int getLeafCount()
1045 Enumeration<?> e = depthFirstEnumeration();
1047 while (e.hasMoreElements())
1049 TreeNode current = (TreeNode) e.nextElement();
1051 if (current.isLeaf())
1058 /** Provides an enumeration of a tree in breadth-first traversal
1061 static class BreadthFirstEnumeration implements Enumeration<TreeNode>
1064 LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
1066 BreadthFirstEnumeration(TreeNode node)
1071 public boolean hasMoreElements()
1073 return !queue.isEmpty();
1076 @SuppressWarnings("unchecked")
1077 public TreeNode nextElement()
1079 if (queue.isEmpty())
1080 throw new NoSuchElementException("No more elements left.");
1082 TreeNode node = queue.removeFirst();
1084 Enumeration<TreeNode> children =
1085 (Enumeration<TreeNode>) node.children();
1086 while (children.hasMoreElements())
1087 queue.add(children.nextElement());
1093 /** Provides an enumeration of a tree traversing it
1096 static class PreorderEnumeration implements Enumeration<TreeNode>
1100 Stack<Enumeration<TreeNode>> childrenEnums =
1101 new Stack<Enumeration<TreeNode>>();
1103 @SuppressWarnings("unchecked")
1104 PreorderEnumeration(TreeNode node)
1107 childrenEnums.push((Enumeration<TreeNode>) node.children());
1110 public boolean hasMoreElements()
1112 return next != null;
1115 public TreeNode nextElement()
1118 throw new NoSuchElementException("No more elements left.");
1120 TreeNode current = next;
1122 Enumeration<TreeNode> children = childrenEnums.peek();
1124 // Retrieves the next element.
1125 next = traverse(children);
1130 @SuppressWarnings("unchecked")
1131 private TreeNode traverse(Enumeration<TreeNode> children)
1133 // If more children are available step down.
1134 if (children.hasMoreElements())
1136 TreeNode child = children.nextElement();
1137 childrenEnums.push((Enumeration<TreeNode>) child.children());
1142 // If no children are left, we return to a higher level.
1143 childrenEnums.pop();
1145 // If there are no more levels left, there is no next
1146 // element to return.
1147 if (childrenEnums.isEmpty())
1151 return traverse(childrenEnums.peek());
1156 /** Provides an enumeration of a tree traversing it
1157 * postordered (= depth-first).
1159 static class PostorderEnumeration implements Enumeration<TreeNode>
1162 Stack<TreeNode> nodes = new Stack<TreeNode>();
1163 Stack<Enumeration<TreeNode>> childrenEnums =
1164 new Stack<Enumeration<TreeNode>>();
1166 @SuppressWarnings("unchecked")
1167 PostorderEnumeration(TreeNode node)
1170 childrenEnums.push((Enumeration<TreeNode>) node.children());
1173 public boolean hasMoreElements()
1175 return !nodes.isEmpty();
1178 public TreeNode nextElement()
1180 if (nodes.isEmpty())
1181 throw new NoSuchElementException("No more elements left!");
1183 Enumeration<TreeNode> children = childrenEnums.peek();
1185 return traverse(children);
1188 @SuppressWarnings("unchecked")
1189 private TreeNode traverse(Enumeration<TreeNode> children)
1191 if (children.hasMoreElements())
1193 TreeNode node = children.nextElement();
1196 Enumeration<TreeNode> newChildren =
1197 (Enumeration<TreeNode>) node.children();
1198 childrenEnums.push(newChildren);
1200 return traverse(newChildren);
1204 childrenEnums.pop();
1206 // Returns the node whose children
1207 // have all been visited. (= postorder)
1208 TreeNode next = nodes.peek();