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 public Enumeration children()
298 if (children.size() == 0)
299 return EMPTY_ENUMERATION;
301 return children.elements();
305 * Set the parent node for this node.
307 * @param node the parent node
309 public void setParent(MutableTreeNode node)
315 * Returns the child node at a given index.
317 * @param index the index
319 * @return the child node
321 public TreeNode getChildAt(int index)
323 return (TreeNode) children.elementAt(index);
327 * Returns the number of children of this node.
329 * @return the number of children
331 public int getChildCount()
333 return children.size();
337 * Returns the index of the specified child node, or -1 if the node is not
338 * in fact a child of this node.
340 * @param node the node (<code>null</code> not permitted).
342 * @return The index of the specified child node, or -1.
344 * @throws IllegalArgumentException if <code>node</code> is <code>null</code>.
346 public int getIndex(TreeNode node)
349 throw new IllegalArgumentException("Null 'node' argument.");
350 return children.indexOf(node);
354 * Sets the flag that controls whether or not this node allows the addition /
355 * insertion of child nodes. If the flag is set to <code>false</code>, any
356 * existing children are removed.
358 * @param allowsChildren the flag.
360 public void setAllowsChildren(boolean allowsChildren)
364 this.allowsChildren = allowsChildren;
372 public boolean getAllowsChildren()
374 return allowsChildren;
378 * Sets the user object for this node
380 * @param userObject the user object
382 public void setUserObject(Object userObject)
384 this.userObject = userObject;
388 * Returns the user object attached to this node. <code>null</code> is
389 * returned when no user object is set.
391 * @return the user object
393 public Object getUserObject()
399 * Removes this node from its parent.
401 public void removeFromParent()
408 * Removes all child nodes from this node.
410 public void removeAllChildren()
412 for (int i = getChildCount() - 1; i >= 0; i--)
417 * Returns <code>true</code> if <code>node</code> is an ancestor of this
418 * tree node, and <code>false</code> otherwise. An ancestor node is any of:
420 * <li>this tree node;</li>
421 * <li>the parent node (if there is one);</li>
422 * <li>any ancestor of the parent node;</li>
424 * If <code>node</code> is <code>null</code>, this method returns
425 * <code>false</code>.
427 * @param node the node (<code>null</code> permitted).
431 public boolean isNodeAncestor(TreeNode node)
436 TreeNode current = this;
438 while (current != null && current != node)
439 current = current.getParent();
441 return current == node;
445 * Returns <code>true</code> if <code>node</code> is a descendant of this
446 * tree node, and <code>false</code> otherwise. A descendant node is any of:
448 * <li>this tree node;</li>
449 * <li>the child nodes belonging to this tree node, if there are any;</li>
450 * <li>any descendants of the child nodes;</li>
452 * If <code>node</code> is <code>null</code>, this method returns
453 * <code>false</code>.
455 * @param node the node (<code>null</code> permitted).
459 public boolean isNodeDescendant(DefaultMutableTreeNode node)
464 TreeNode current = node;
466 while (current != null
468 current = current.getParent();
470 return current == this;
480 public TreeNode getSharedAncestor(DefaultMutableTreeNode node)
482 TreeNode current = this;
483 ArrayList<TreeNode> list = new ArrayList<TreeNode>();
485 while (current != null)
488 current = current.getParent();
493 while (current != null)
495 if (list.contains(current))
498 current = current.getParent();
511 public boolean isNodeRelated(DefaultMutableTreeNode node)
516 return node.getRoot() == getRoot();
524 public int getDepth()
526 if ((! allowsChildren)
527 || children.size() == 0)
530 Stack<Integer> stack = new Stack<Integer>();
531 stack.push(new Integer(0));
532 TreeNode node = getChildAt(0);
536 while (! stack.empty())
538 if (node.getChildCount() != 0)
540 node = node.getChildAt(0);
541 stack.push(new Integer(0));
554 node = node.getParent();
555 size = node.getChildCount();
556 index = stack.pop().intValue() + 1;
564 node = node.getChildAt(index);
565 stack.push(new Integer(index));
579 public int getLevel()
582 TreeNode current = this;
586 current = current.getParent();
589 while (current != null);
602 protected TreeNode[] getPathToRoot(TreeNode node, int depth)
609 return new TreeNode[depth];
612 TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
613 path[path.length - depth - 1] = node;
622 public Object[] getUserObjectPath()
624 TreeNode[] path = getPathToRoot(this, 0);
625 Object[] object = new Object[path.length];
627 for (int index = 0; index < path.length; ++index)
628 object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject();
634 * Returns the root node by iterating the parents of this node.
636 * @return the root node
638 public TreeNode getRoot()
640 TreeNode current = this;
641 TreeNode check = current.getParent();
643 while (check != null)
646 check = current.getParent();
653 * Tells whether this node is the root node or not.
655 * @return <code>true</code> if this is the root node,
656 * <code>false</code>otherwise
658 public boolean isRoot()
660 return parent == null;
666 * @return DefaultMutableTreeNode
668 public DefaultMutableTreeNode getNextNode()
670 // Return first child.
671 if (getChildCount() != 0)
672 return (DefaultMutableTreeNode) getChildAt(0);
674 // Return next sibling (if needed the sibling of some parent).
675 DefaultMutableTreeNode node = this;
676 DefaultMutableTreeNode sibling;
680 sibling = node.getNextSibling();
681 node = (DefaultMutableTreeNode) node.getParent();
683 while (sibling == null &&
693 * @return DefaultMutableTreeNode
695 public DefaultMutableTreeNode getPreviousNode()
697 // Return null if no parent.
701 DefaultMutableTreeNode sibling = getPreviousSibling();
703 // Return parent if no sibling.
705 return (DefaultMutableTreeNode) parent;
707 // Return last leaf of sibling.
708 if (sibling.getChildCount() != 0)
709 return sibling.getLastLeaf();
716 * preorderEnumeration
718 * @return Enumeration
720 public Enumeration preorderEnumeration()
722 return new PreorderEnumeration(this);
726 * postorderEnumeration
728 * @return Enumeration
730 public Enumeration postorderEnumeration()
732 return new PostorderEnumeration(this);
736 * breadthFirstEnumeration
738 * @return Enumeration
740 public Enumeration breadthFirstEnumeration()
742 return new BreadthFirstEnumeration(this);
746 * depthFirstEnumeration
748 * @return Enumeration
750 public Enumeration depthFirstEnumeration()
752 return postorderEnumeration();
756 * pathFromAncestorEnumeration
760 * @return Enumeration
762 public Enumeration pathFromAncestorEnumeration(TreeNode node)
765 throw new IllegalArgumentException();
767 TreeNode parent = this;
768 Vector<TreeNode> nodes = new Vector<TreeNode>();
771 while (parent != node && parent != null)
773 parent = parent.getParent();
774 nodes.add(0, parent);
778 throw new IllegalArgumentException();
780 return nodes.elements();
784 * Returns <code>true</code> if <code>node</code> is a child of this tree
785 * node, and <code>false</code> otherwise. If <code>node</code> is
786 * <code>null</code>, this method returns <code>false</code>.
788 * @param node the node (<code>null</code> permitted).
792 public boolean isNodeChild(TreeNode node)
797 return node.getParent() == this;
801 * Returns the first child node belonging to this tree node.
803 * @return The first child node.
805 * @throws NoSuchElementException if this tree node has no children.
807 public TreeNode getFirstChild()
809 return (TreeNode) children.firstElement();
813 * Returns the last child node belonging to this tree node.
815 * @return The last child node.
817 * @throws NoSuchElementException if this tree node has no children.
819 public TreeNode getLastChild()
821 return (TreeNode) children.lastElement();
825 * Returns the next child after the specified <code>node</code>, or
826 * <code>null</code> if there is no child after the specified
829 * @param node a child of this node (<code>null</code> not permitted).
831 * @return The next child, or <code>null</code>.
833 * @throws IllegalArgumentException if <code>node</code> is not a child of
834 * this node, or is <code>null</code>.
836 public TreeNode getChildAfter(TreeNode node)
838 if (node == null || node.getParent() != this)
839 throw new IllegalArgumentException();
841 int index = getIndex(node) + 1;
843 if (index == getChildCount())
846 return getChildAt(index);
850 * Returns the previous child before the specified <code>node</code>, or
851 * <code>null</code> if there is no child before the specified
854 * @param node a child of this node (<code>null</code> not permitted).
856 * @return The previous child, or <code>null</code>.
858 * @throws IllegalArgumentException if <code>node</code> is not a child of
859 * this node, or is <code>null</code>.
861 public TreeNode getChildBefore(TreeNode node)
863 if (node == null || node.getParent() != this)
864 throw new IllegalArgumentException();
866 int index = getIndex(node) - 1;
871 return getChildAt(index);
875 * Returns <code>true</code> if this tree node and <code>node</code> share
876 * the same parent. If <code>node</code> is this tree node, the method
877 * returns <code>true</code> and if <code>node</code> is <code>null</code>
878 * this method returns <code>false</code>.
880 * @param node the node (<code>null</code> permitted).
884 public boolean isNodeSibling(TreeNode node)
890 return node.getParent() == getParent() && getParent() != null;
894 * Returns the number of siblings for this tree node. If the tree node has
895 * a parent, this method returns the child count for the parent, otherwise
896 * it returns <code>1</code>.
898 * @return The sibling count.
900 public int getSiblingCount()
905 return parent.getChildCount();
909 * Returns the next sibling for this tree node. If this node has no parent,
910 * or this node is the last child of its parent, this method returns
913 * @return The next sibling, or <code>null</code>.
915 public DefaultMutableTreeNode getNextSibling()
920 int index = parent.getIndex(this) + 1;
922 if (index == parent.getChildCount())
925 return (DefaultMutableTreeNode) parent.getChildAt(index);
929 * Returns the previous sibling for this tree node. If this node has no
930 * parent, or this node is the first child of its parent, this method returns
933 * @return The previous sibling, or <code>null</code>.
935 public DefaultMutableTreeNode getPreviousSibling()
940 int index = parent.getIndex(this) - 1;
945 return (DefaultMutableTreeNode) parent.getChildAt(index);
949 * Returns <code>true</code> if this tree node is a lead node (that is, it
950 * has no children), and <code>false</otherwise>.
954 public boolean isLeaf()
956 return children.size() == 0;
960 * Returns the first leaf node that is a descendant of this node. Recall
961 * that a node is its own descendant, so if this node has no children then
962 * it is returned as the first leaf.
964 * @return The first leaf node.
966 public DefaultMutableTreeNode getFirstLeaf()
968 TreeNode current = this;
970 while (current.getChildCount() > 0)
971 current = current.getChildAt(0);
973 return (DefaultMutableTreeNode) current;
977 * Returns the last leaf node that is a descendant of this node. Recall
978 * that a node is its own descendant, so if this node has no children then
979 * it is returned as the last leaf.
981 * @return The first leaf node.
983 public DefaultMutableTreeNode getLastLeaf()
985 TreeNode current = this;
986 int size = current.getChildCount();
990 current = current.getChildAt(size - 1);
991 size = current.getChildCount();
994 return (DefaultMutableTreeNode) current;
998 * Returns the next leaf node after this tree node.
1000 * @return The next leaf node, or <code>null</code>.
1002 public DefaultMutableTreeNode getNextLeaf()
1004 // if there is a next sibling, return its first leaf
1005 DefaultMutableTreeNode sibling = getNextSibling();
1006 if (sibling != null)
1007 return sibling.getFirstLeaf();
1008 // otherwise move up one level and try again...
1010 return ((DefaultMutableTreeNode) parent).getNextLeaf();
1015 * Returns the previous leaf node before this tree node.
1017 * @return The previous leaf node, or <code>null</code>.
1019 public DefaultMutableTreeNode getPreviousLeaf()
1021 // if there is a previous sibling, return its last leaf
1022 DefaultMutableTreeNode sibling = getPreviousSibling();
1023 if (sibling != null)
1024 return sibling.getLastLeaf();
1025 // otherwise move up one level and try again...
1027 return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
1036 public int getLeafCount()
1039 Enumeration e = depthFirstEnumeration();
1041 while (e.hasMoreElements())
1043 TreeNode current = (TreeNode) e.nextElement();
1045 if (current.isLeaf())
1052 /** Provides an enumeration of a tree in breadth-first traversal
1055 static class BreadthFirstEnumeration implements Enumeration<TreeNode>
1058 LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
1060 BreadthFirstEnumeration(TreeNode node)
1065 public boolean hasMoreElements()
1067 return !queue.isEmpty();
1070 @SuppressWarnings("unchecked")
1071 public TreeNode nextElement()
1073 if (queue.isEmpty())
1074 throw new NoSuchElementException("No more elements left.");
1076 TreeNode node = queue.removeFirst();
1078 Enumeration<TreeNode> children =
1079 (Enumeration<TreeNode>) node.children();
1080 while (children.hasMoreElements())
1081 queue.add(children.nextElement());
1087 /** Provides an enumeration of a tree traversing it
1090 static class PreorderEnumeration implements Enumeration<TreeNode>
1094 Stack<Enumeration<TreeNode>> childrenEnums =
1095 new Stack<Enumeration<TreeNode>>();
1097 @SuppressWarnings("unchecked")
1098 PreorderEnumeration(TreeNode node)
1101 childrenEnums.push((Enumeration<TreeNode>) node.children());
1104 public boolean hasMoreElements()
1106 return next != null;
1109 public TreeNode nextElement()
1112 throw new NoSuchElementException("No more elements left.");
1114 TreeNode current = next;
1116 Enumeration<TreeNode> children = childrenEnums.peek();
1118 // Retrieves the next element.
1119 next = traverse(children);
1124 @SuppressWarnings("unchecked")
1125 private TreeNode traverse(Enumeration<TreeNode> children)
1127 // If more children are available step down.
1128 if (children.hasMoreElements())
1130 TreeNode child = children.nextElement();
1131 childrenEnums.push((Enumeration<TreeNode>) child.children());
1136 // If no children are left, we return to a higher level.
1137 childrenEnums.pop();
1139 // If there are no more levels left, there is no next
1140 // element to return.
1141 if (childrenEnums.isEmpty())
1145 return traverse(childrenEnums.peek());
1150 /** Provides an enumeration of a tree traversing it
1151 * postordered (= depth-first).
1153 static class PostorderEnumeration implements Enumeration<TreeNode>
1156 Stack<TreeNode> nodes = new Stack<TreeNode>();
1157 Stack<Enumeration<TreeNode>> childrenEnums =
1158 new Stack<Enumeration<TreeNode>>();
1160 @SuppressWarnings("unchecked")
1161 PostorderEnumeration(TreeNode node)
1164 childrenEnums.push((Enumeration<TreeNode>) node.children());
1167 public boolean hasMoreElements()
1169 return !nodes.isEmpty();
1172 public TreeNode nextElement()
1174 if (nodes.isEmpty())
1175 throw new NoSuchElementException("No more elements left!");
1177 Enumeration<TreeNode> children = childrenEnums.peek();
1179 return traverse(children);
1182 @SuppressWarnings("unchecked")
1183 private TreeNode traverse(Enumeration<TreeNode> children)
1185 if (children.hasMoreElements())
1187 TreeNode node = children.nextElement();
1190 Enumeration<TreeNode> newChildren =
1191 (Enumeration<TreeNode>) node.children();
1192 childrenEnums.push(newChildren);
1194 return traverse(newChildren);
1198 childrenEnums.pop();
1200 // Returns the node whose children
1201 // have all been visited. (= postorder)
1202 TreeNode next = nodes.peek();