1 /* DefaultMutableTreeNode.java --
2 Copyright (C) 2002, 2004, 2005 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., 59 Temple Place, Suite 330, 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
.Stack
;
50 import java
.util
.Vector
;
53 * DefaultMutableTreeNode
55 * @author Andrew Selkirk
57 public class DefaultMutableTreeNode
58 implements Cloneable
, MutableTreeNode
, Serializable
60 private static final long serialVersionUID
= -4298474751201349152L;
65 public static final Enumeration EMPTY_ENUMERATION
=
66 EmptyEnumeration
.getInstance();
71 protected MutableTreeNode parent
;
76 protected Vector children
= new Vector();
81 protected transient Object userObject
;
86 protected boolean allowsChildren
;
89 * Creates a <code>DefaultMutableTreeNode</code> object.
90 * This node allows to add child nodes.
92 public DefaultMutableTreeNode()
98 * Creates a <code>DefaultMutableTreeNode</code> object with the given
99 * user object attached to it. This node allows to add child nodes.
101 * @param userObject the user object
103 public DefaultMutableTreeNode(Object userObject
)
105 this(userObject
, true);
109 * Creates a <code>DefaultMutableTreeNode</code> object with the given
110 * user object attached to it.
112 * @param userObject the user object
113 * @param allowsChildren <code>true</code> if the code allows to add child
114 * nodes, <code>false</code> otherwise
116 public DefaultMutableTreeNode(Object userObject
, boolean allowsChildren
)
118 this.userObject
= userObject
;
119 this.allowsChildren
= allowsChildren
;
127 public Object
clone()
131 return super.clone();
132 // TODO: Do we need to do more here ?
134 catch (CloneNotSupportedException e
)
136 // This never happens.
142 * Returns a string representation of this node
144 * @return a human-readable String representing this node
146 public String
toString()
148 if (userObject
== null)
151 return userObject
.toString();
155 * Adds a new child node to this node.
157 * @param child the child node
159 * @throws IllegalArgumentException if <code>child</code> is null
160 * @throws IllegalStateException if the node does not allow children
162 public void add(MutableTreeNode child
)
165 throw new IllegalArgumentException();
167 if (! allowsChildren
)
168 throw new IllegalStateException();
171 child
.setParent(this);
175 * Returns the parent node of this node.
177 * @return the parent node
179 public TreeNode
getParent()
185 * Removes the child with the given index from this node
187 * @param index the index
189 public void remove(int index
)
191 children
.remove(index
);
195 * Removes the given child from this node.
197 * @param node the child node
199 public void remove(MutableTreeNode node
)
201 children
.remove(node
);
207 * @param stream the output stream
209 * @exception IOException If an error occurs
211 private void writeObject(ObjectOutputStream stream
)
214 // TODO: Implement me.
220 * @param stream the input stream
222 * @exception IOException If an error occurs
223 * @exception ClassNotFoundException TODO
225 private void readObject(ObjectInputStream stream
)
226 throws IOException
, ClassNotFoundException
228 // TODO: Implement me.
232 * Inserts given child node at the given index.
234 * @param node the child node
235 * @param value the index.
237 public void insert(MutableTreeNode node
, int index
)
239 children
.insertElementAt(node
, index
);
243 * Returns a path to this node from the root.
245 * @return an array of tree nodes
247 public TreeNode
[] getPath()
249 return getPathToRoot(this, 0);
253 * Returns an enumeration containing all children of this node.
254 * <code>EMPTY_ENUMERATION</code> is returned if this node has no children.
256 * @return an enumeration of tree nodes
258 public Enumeration
children()
260 if (children
.size() == 0)
261 return EMPTY_ENUMERATION
;
263 return children
.elements();
267 * Set the parent node for this node.
269 * @param node the parent node
271 public void setParent(MutableTreeNode node
)
277 * Returns the child node at a given index.
279 * @param index the index
281 * @return the child node
283 public TreeNode
getChildAt(int index
)
285 return (TreeNode
) children
.elementAt(index
);
289 * Returns the number of children of this node.
291 * @return the number of children
293 public int getChildCount()
295 return children
.size();
299 * Returns the child index for a given node.
301 * @param node this node
305 public int getIndex(TreeNode node
)
307 return children
.indexOf(node
);
313 * @param allowsChildren TODO
315 public void setAllowsChildren(boolean allowsChildren
)
317 this.allowsChildren
= allowsChildren
;
325 public boolean getAllowsChildren()
327 return allowsChildren
;
331 * Sets the user object for this node
333 * @param userObject the user object
335 public void setUserObject(Object userObject
)
337 this.userObject
= userObject
;
341 * Returns the user object attached to this node. <code>null</code> is
342 * returned when no user object is set.
344 * @return the user object
346 public Object
getUserObject()
352 * Removes this node from its parent.
354 public void removeFromParent()
356 // FIXME: IS this implementation really correct ?
361 * Removes all child nodes from this node.
363 public void removeAllChildren()
365 children
.removeAllElements();
375 public boolean isNodeAncestor(TreeNode node
)
380 TreeNode current
= this;
382 while (current
!= null
384 current
= current
.getParent();
386 return current
== node
;
396 public boolean isNodeDescendant(DefaultMutableTreeNode node
)
401 TreeNode current
= node
;
403 while (current
!= null
405 current
= current
.getParent();
407 return current
== this;
417 public TreeNode
getSharedAncestor(DefaultMutableTreeNode node
)
419 TreeNode current
= this;
420 ArrayList list
= new ArrayList();
422 while (current
!= null)
425 current
= current
.getParent();
430 while (current
!= null)
432 if (list
.contains(current
))
435 current
= current
.getParent();
448 public boolean isNodeRelated(DefaultMutableTreeNode node
)
453 return node
.getRoot() == getRoot();
461 public int getDepth()
463 if ((! allowsChildren
)
464 || children
.size() == 0)
467 Stack stack
= new Stack();
468 stack
.push(new Integer(0));
469 TreeNode node
= getChildAt(0);
473 while (! stack
.empty())
475 if (node
.getChildCount() != 0)
477 node
= node
.getChildAt(0);
478 stack
.push(new Integer(0));
491 node
= node
.getParent();
492 size
= node
.getChildCount();
493 index
= ((Integer
) stack
.pop()).intValue() + 1;
501 node
= node
.getChildAt(index
);
502 stack
.push(new Integer(index
));
516 public int getLevel()
519 TreeNode current
= this;
523 current
= current
.getParent();
526 while (current
!= null);
539 protected TreeNode
[] getPathToRoot(TreeNode node
, int depth
)
546 return new TreeNode
[depth
];
549 TreeNode
[] path
= getPathToRoot(node
.getParent(), depth
+ 1);
550 path
[path
.length
- depth
- 1] = node
;
559 public Object
[] getUserObjectPath()
561 TreeNode
[] path
= getPathToRoot(this, 0);
562 Object
[] object
= new Object
[path
.length
];
564 for (int index
= 0; index
< path
.length
; ++index
)
565 object
[index
] = ((DefaultMutableTreeNode
) path
[index
]).getUserObject();
571 * Returns the root node by iterating the parents of this node.
573 * @return the root node
575 public TreeNode
getRoot()
577 TreeNode current
= this;
578 TreeNode check
= current
.getParent();
580 while (check
!= null)
583 check
= current
.getParent();
590 * Tells whether this node is the root node or not.
592 * @return <code>true</code> if this is the root node,
593 * <code>false</code>otherwise
595 public boolean isRoot()
597 return parent
== null;
603 * @return DefaultMutableTreeNode
605 public DefaultMutableTreeNode
getNextNode()
607 // Return first child.
608 if (getChildCount() != 0)
609 return (DefaultMutableTreeNode
) getChildAt(0);
611 // Return next sibling (if needed the sibling of some parent).
612 DefaultMutableTreeNode node
= this;
613 DefaultMutableTreeNode sibling
;
617 sibling
= node
.getNextSibling();
618 node
= (DefaultMutableTreeNode
) node
.getParent();
620 while (sibling
== null &&
630 * @return DefaultMutableTreeNode
632 public DefaultMutableTreeNode
getPreviousNode()
634 // Return null if no parent.
638 DefaultMutableTreeNode sibling
= getPreviousSibling();
640 // Return parent if no sibling.
642 return (DefaultMutableTreeNode
) parent
;
644 // Return last leaf of sibling.
645 if (sibling
.getChildCount() != 0)
646 return sibling
.getLastLeaf();
653 * preorderEnumeration
655 * @return Enumeration
657 public Enumeration
preorderEnumeration()
659 return null; // TODO: Implement me.
663 * postorderEnumeration
665 * @return Enumeration
667 public Enumeration
postorderEnumeration()
669 return null; // TODO: Implement me.
673 * breadthFirstEnumeration
675 * @return Enumeration
677 public Enumeration
breadthFirstEnumeration()
679 return null; // TODO: Implement me.
683 * depthFirstEnumeration
685 * @return Enumeration
687 public Enumeration
depthFirstEnumeration()
689 return postorderEnumeration();
693 * pathFromAncestorEnumeration
697 * @return Enumeration
699 public Enumeration
pathFromAncestorEnumeration(TreeNode node
)
702 throw new IllegalArgumentException();
704 TreeNode parent
= this;
705 Vector nodes
= new Vector();
708 while (parent
!= node
&& parent
!= null)
710 parent
= parent
.getParent();
711 nodes
.add(0, parent
);
715 throw new IllegalArgumentException();
717 return nodes
.elements();
727 public boolean isNodeChild(TreeNode node
)
732 return node
.getParent() == this;
740 public TreeNode
getFirstChild()
742 return (TreeNode
) children
.firstElement();
750 public TreeNode
getLastChild()
752 return (TreeNode
) children
.lastElement();
762 public TreeNode
getChildAfter(TreeNode node
)
765 || node
.getParent() != this)
766 throw new IllegalArgumentException();
768 int index
= getIndex(node
) + 1;
770 if (index
== getChildCount())
773 return getChildAt(index
);
783 public TreeNode
getChildBefore(TreeNode node
)
786 || node
.getParent() != this)
787 throw new IllegalArgumentException();
789 int index
= getIndex(node
) - 1;
794 return getChildAt(index
);
804 public boolean isNodeSibling(TreeNode node
)
809 return (node
.getParent() == getParent()
810 && getParent() != null);
818 public int getSiblingCount()
823 return parent
.getChildCount();
829 * @return DefaultMutableTreeNode
831 public DefaultMutableTreeNode
getNextSibling()
836 int index
= parent
.getIndex(this) + 1;
838 if (index
== parent
.getChildCount())
841 return (DefaultMutableTreeNode
) parent
.getChildAt(index
);
847 * @return DefaultMutableTreeNode
849 public DefaultMutableTreeNode
getPreviousSibling()
854 int index
= parent
.getIndex(this) - 1;
859 return (DefaultMutableTreeNode
) parent
.getChildAt(index
);
867 public boolean isLeaf()
869 return children
.size() == 0;
875 * @return DefaultMutableTreeNode
877 public DefaultMutableTreeNode
getFirstLeaf()
879 TreeNode current
= this;
881 while (current
.getChildCount() > 0)
882 current
= current
.getChildAt(0);
884 return (DefaultMutableTreeNode
) current
;
890 * @return DefaultMutableTreeNode
892 public DefaultMutableTreeNode
getLastLeaf()
894 TreeNode current
= this;
895 int size
= current
.getChildCount();
899 current
= current
.getChildAt(size
- 1);
900 size
= current
.getChildCount();
903 return (DefaultMutableTreeNode
) current
;
909 * @return DefaultMutableTreeNode
911 public DefaultMutableTreeNode
getNextLeaf()
917 //return parent.getChildAfter(this);
923 * @return DefaultMutableTreeNode
925 public DefaultMutableTreeNode
getPreviousLeaf()
931 //return parent.getChildBefore(this);
939 public int getLeafCount()
942 Enumeration e
= depthFirstEnumeration();
944 while (e
.hasMoreElements())
946 TreeNode current
= (TreeNode
) e
.nextElement();
948 if (current
.isLeaf())