mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1224 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1224 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* DefaultMutableTreeNode.java --
 | |
|    Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package javax.swing.tree;
 | |
| 
 | |
| import gnu.java.util.EmptyEnumeration;
 | |
| 
 | |
| import java.io.IOException;
 | |
| import java.io.ObjectInputStream;
 | |
| import java.io.ObjectOutputStream;
 | |
| import java.io.Serializable;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Enumeration;
 | |
| import java.util.LinkedList;
 | |
| import java.util.NoSuchElementException;
 | |
| import java.util.Stack;
 | |
| import java.util.Vector;
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * A default implementation of the {@link MutableTreeNode} interface.
 | |
|  *
 | |
|  * @author Andrew Selkirk
 | |
|  * @author Robert Schuster (robertschuster@fsfe.org)
 | |
|  */
 | |
| public class DefaultMutableTreeNode
 | |
|   implements Cloneable, MutableTreeNode, Serializable
 | |
| {
 | |
|   private static final long serialVersionUID = -4298474751201349152L;
 | |
| 
 | |
|   /**
 | |
|    * An empty enumeration, returned by {@link #children()} if a node has no
 | |
|    * children.
 | |
|    */
 | |
|   public static final Enumeration<TreeNode> EMPTY_ENUMERATION =
 | |
|     new EmptyEnumeration<TreeNode>();
 | |
| 
 | |
|   /**
 | |
|    * The parent of this node (possibly <code>null</code>).
 | |
|    */
 | |
|   protected MutableTreeNode parent;
 | |
| 
 | |
|   /**
 | |
|    * The child nodes for this node (may be empty).
 | |
|    */
 | |
|   protected Vector<MutableTreeNode> children = new Vector<MutableTreeNode>();
 | |
| 
 | |
|   /**
 | |
|    * userObject
 | |
|    */
 | |
|   protected transient Object userObject;
 | |
| 
 | |
|   /**
 | |
|    * allowsChildren
 | |
|    */
 | |
|   protected boolean allowsChildren;
 | |
| 
 | |
|   /**
 | |
|    * Creates a <code>DefaultMutableTreeNode</code> object.
 | |
|    * This is equivalent to <code>DefaultMutableTreeNode(null, true)</code>.
 | |
|    */
 | |
|   public DefaultMutableTreeNode()
 | |
|   {
 | |
|     this(null, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a <code>DefaultMutableTreeNode</code> object with the given
 | |
|    * user object attached to it. This is equivalent to
 | |
|    * <code>DefaultMutableTreeNode(userObject, true)</code>.
 | |
|    *
 | |
|    * @param userObject the user object (<code>null</code> permitted).
 | |
|    */
 | |
|   public DefaultMutableTreeNode(Object userObject)
 | |
|   {
 | |
|     this(userObject, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a <code>DefaultMutableTreeNode</code> object with the given
 | |
|    * user object attached to it.
 | |
|    *
 | |
|    * @param userObject the user object (<code>null</code> permitted).
 | |
|    * @param allowsChildren <code>true</code> if the code allows to add child
 | |
|    * nodes, <code>false</code> otherwise
 | |
|    */
 | |
|   public DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
 | |
|   {
 | |
|     this.userObject = userObject;
 | |
|     this.allowsChildren = allowsChildren;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a clone of the node.  The clone contains a shallow copy of the
 | |
|    * user object, and does not copy the parent node or the child nodes.
 | |
|    *
 | |
|    * @return A clone of the node.
 | |
|    */
 | |
|   public Object clone()
 | |
|   {
 | |
|     return new DefaultMutableTreeNode(this.userObject, this.allowsChildren);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a string representation of the node.  This implementation returns
 | |
|    * <code>getUserObject().toString()</code>, or <code>null</code> if there
 | |
|    * is no user object.
 | |
|    *
 | |
|    * @return A string representation of the node (possibly <code>null</code>).
 | |
|    */
 | |
|   public String toString()
 | |
|   {
 | |
|     if (userObject == null)
 | |
|       return null;
 | |
| 
 | |
|     return userObject.toString();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Adds a new child node to this node and sets this node as the parent of
 | |
|    * the child node.  The child node must not be an ancestor of this node.
 | |
|    * If the tree uses the {@link DefaultTreeModel}, you must subsequently
 | |
|    * call {@link DefaultTreeModel#reload(TreeNode)}.
 | |
|    *
 | |
|    * @param child the child node (<code>null</code> not permitted).
 | |
|    *
 | |
|    * @throws IllegalStateException if {@link #getAllowsChildren()} returns
 | |
|    *     <code>false</code>.
 | |
|    * @throws IllegalArgumentException if {@link #isNodeAncestor} returns
 | |
|    *     <code>true</code>.
 | |
|    * @throws IllegalArgumentException if <code>child</code> is
 | |
|    *     <code>null</code>.
 | |
|    */
 | |
|   public void add(MutableTreeNode child)
 | |
|   {
 | |
|     if (! allowsChildren)
 | |
|       throw new IllegalStateException();
 | |
| 
 | |
|     if (child == null)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     if (isNodeAncestor(child))
 | |
|       throw new IllegalArgumentException("Cannot add ancestor node.");
 | |
| 
 | |
|     children.add(child);
 | |
|     child.setParent(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the parent node of this node.
 | |
|    *
 | |
|    * @return The parent node (possibly <code>null</code>).
 | |
|    */
 | |
|   public TreeNode getParent()
 | |
|   {
 | |
|     return parent;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes the child with the given index from this node.
 | |
|    *
 | |
|    * @param index the index (in the range <code>0</code> to
 | |
|    *     <code>getChildCount() - 1</code>).
 | |
|    *
 | |
|    * @throws ArrayIndexOutOfBoundsException if <code>index</code> is outside
 | |
|    *         the valid range.
 | |
|    */
 | |
|   public void remove(int index)
 | |
|   {
 | |
|     MutableTreeNode child = children.remove(index);
 | |
|     child.setParent(null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes the given child from this node and sets its parent to
 | |
|    * <code>null</code>.
 | |
|    *
 | |
|    * @param node the child node (<code>null</code> not permitted).
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>node</code> is not a child of
 | |
|    *     this node.
 | |
|    * @throws IllegalArgumentException if <code>node</code> is null.
 | |
|    */
 | |
|   public void remove(MutableTreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       throw new IllegalArgumentException("Null 'node' argument.");
 | |
|     if (node.getParent() != this)
 | |
|       throw new IllegalArgumentException(
 | |
|           "The given 'node' is not a child of this node.");
 | |
|     children.remove(node);
 | |
|     node.setParent(null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * writeObject
 | |
|    *
 | |
|    * @param stream the output stream
 | |
|    *
 | |
|    * @exception IOException If an error occurs
 | |
|    */
 | |
|   private void writeObject(ObjectOutputStream stream)
 | |
|     throws IOException
 | |
|   {
 | |
|     // TODO: Implement me.
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * readObject
 | |
|    *
 | |
|    * @param stream the input stream
 | |
|    *
 | |
|    * @exception IOException If an error occurs
 | |
|    * @exception ClassNotFoundException TODO
 | |
|    */
 | |
|   private void readObject(ObjectInputStream stream)
 | |
|     throws IOException, ClassNotFoundException
 | |
|   {
 | |
|     // TODO: Implement me.
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Inserts given child node at the given index.
 | |
|    *
 | |
|    * @param node the child node (<code>null</code> not permitted).
 | |
|    * @param index the index.
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>node</code> is
 | |
|    *     </code>null</code>.
 | |
|    */
 | |
|   public void insert(MutableTreeNode node, int index)
 | |
|   {
 | |
|     if (! allowsChildren)
 | |
|       throw new IllegalStateException();
 | |
| 
 | |
|     if (node == null)
 | |
|       throw new IllegalArgumentException("Null 'node' argument.");
 | |
| 
 | |
|     if (isNodeAncestor(node))
 | |
|       throw new IllegalArgumentException("Cannot insert ancestor node.");
 | |
| 
 | |
|     children.insertElementAt(node, index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a path to this node from the root.
 | |
|    *
 | |
|    * @return an array of tree nodes
 | |
|    */
 | |
|   public TreeNode[] getPath()
 | |
|   {
 | |
|     return getPathToRoot(this, 0);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns an enumeration containing all children of this node.
 | |
|    * <code>EMPTY_ENUMERATION</code> is returned if this node has no children.
 | |
|    *
 | |
|    * @return an enumeration of tree nodes
 | |
|    */
 | |
|   @SuppressWarnings("rawtypes") // Required for API compatibility
 | |
|   public Enumeration children()
 | |
|   {
 | |
|     if (children.size() == 0)
 | |
|       return EMPTY_ENUMERATION;
 | |
| 
 | |
|     return children.elements();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Set the parent node for this node.
 | |
|    *
 | |
|    * @param node the parent node
 | |
|    */
 | |
|   public void setParent(MutableTreeNode node)
 | |
|   {
 | |
|     parent = node;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the child node at a given index.
 | |
|    *
 | |
|    * @param index the index
 | |
|    *
 | |
|    * @return the child node
 | |
|    */
 | |
|   public TreeNode getChildAt(int index)
 | |
|   {
 | |
|     return children.elementAt(index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the number of children of this node.
 | |
|    *
 | |
|    * @return the number of children
 | |
|    */
 | |
|   public int getChildCount()
 | |
|   {
 | |
|     return children.size();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the index of the specified child node, or -1 if the node is not
 | |
|    * in fact a child of this node.
 | |
|    *
 | |
|    * @param node  the node (<code>null</code> not permitted).
 | |
|    *
 | |
|    * @return The index of the specified child node, or -1.
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>node</code> is <code>null</code>.
 | |
|    */
 | |
|   public int getIndex(TreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       throw new IllegalArgumentException("Null 'node' argument.");
 | |
|     return children.indexOf(node);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the flag that controls whether or not this node allows the addition /
 | |
|    * insertion of child nodes.  If the flag is set to <code>false</code>, any
 | |
|    * existing children are removed.
 | |
|    *
 | |
|    * @param allowsChildren  the flag.
 | |
|    */
 | |
|   public void setAllowsChildren(boolean allowsChildren)
 | |
|   {
 | |
|     if (!allowsChildren)
 | |
|       removeAllChildren();
 | |
|     this.allowsChildren = allowsChildren;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getAllowsChildren
 | |
|    *
 | |
|    * @return boolean
 | |
|    */
 | |
|   public boolean getAllowsChildren()
 | |
|   {
 | |
|     return allowsChildren;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the user object for this node
 | |
|    *
 | |
|    * @param userObject the user object
 | |
|    */
 | |
|   public void setUserObject(Object userObject)
 | |
|   {
 | |
|     this.userObject = userObject;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the user object attached to this node. <code>null</code> is
 | |
|    * returned when no user object is set.
 | |
|    *
 | |
|    * @return the user object
 | |
|    */
 | |
|   public Object getUserObject()
 | |
|   {
 | |
|     return userObject;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes this node from its parent.
 | |
|    */
 | |
|   public void removeFromParent()
 | |
|   {
 | |
|     parent.remove(this);
 | |
|     parent = null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes all child nodes from this node.
 | |
|    */
 | |
|   public void removeAllChildren()
 | |
|   {
 | |
|     for (int i = getChildCount() - 1; i >= 0; i--)
 | |
|       remove(i);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if <code>node</code> is an ancestor of this
 | |
|    * tree node, and <code>false</code> otherwise.  An ancestor node is any of:
 | |
|    * <ul>
 | |
|    * <li>this tree node;</li>
 | |
|    * <li>the parent node (if there is one);</li>
 | |
|    * <li>any ancestor of the parent node;</li>
 | |
|    * </ul>
 | |
|    * If <code>node</code> is <code>null</code>, this method returns
 | |
|    * <code>false</code>.
 | |
|    *
 | |
|    * @param node  the node (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return A boolean.
 | |
|    */
 | |
|   public boolean isNodeAncestor(TreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       return false;
 | |
| 
 | |
|     TreeNode current = this;
 | |
| 
 | |
|     while (current != null && current != node)
 | |
|       current = current.getParent();
 | |
| 
 | |
|     return current == node;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if <code>node</code> is a descendant of this
 | |
|    * tree node, and <code>false</code> otherwise.  A descendant node is any of:
 | |
|    * <ul>
 | |
|    * <li>this tree node;</li>
 | |
|    * <li>the child nodes belonging to this tree node, if there are any;</li>
 | |
|    * <li>any descendants of the child nodes;</li>
 | |
|    * </ul>
 | |
|    * If <code>node</code> is <code>null</code>, this method returns
 | |
|    * <code>false</code>.
 | |
|    *
 | |
|    * @param node  the node (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return A boolean.
 | |
|    */
 | |
|   public boolean isNodeDescendant(DefaultMutableTreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       return false;
 | |
| 
 | |
|     TreeNode current = node;
 | |
| 
 | |
|     while (current != null
 | |
|            && current != this)
 | |
|       current = current.getParent();
 | |
| 
 | |
|     return current == this;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getSharedAncestor
 | |
|    *
 | |
|    * @param node TODO
 | |
|    *
 | |
|    * @return TreeNode
 | |
|    */
 | |
|   public TreeNode getSharedAncestor(DefaultMutableTreeNode node)
 | |
|   {
 | |
|     TreeNode current = this;
 | |
|     ArrayList<TreeNode> list = new ArrayList<TreeNode>();
 | |
| 
 | |
|     while (current != null)
 | |
|       {
 | |
|         list.add(current);
 | |
|         current = current.getParent();
 | |
|       }
 | |
| 
 | |
|     current = node;
 | |
| 
 | |
|     while (current != null)
 | |
|       {
 | |
|         if (list.contains(current))
 | |
|           return current;
 | |
| 
 | |
|         current = current.getParent();
 | |
|       }
 | |
| 
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * isNodeRelated
 | |
|    *
 | |
|    * @param node TODO
 | |
|    *
 | |
|    * @return boolean
 | |
|    */
 | |
|   public boolean isNodeRelated(DefaultMutableTreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       return false;
 | |
| 
 | |
|     return node.getRoot() == getRoot();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getDepth
 | |
|    *
 | |
|    * @return int
 | |
|    */
 | |
|   public int getDepth()
 | |
|   {
 | |
|     if ((! allowsChildren)
 | |
|         || children.size() == 0)
 | |
|       return 0;
 | |
| 
 | |
|     Stack<Integer> stack = new Stack<Integer>();
 | |
|     stack.push(new Integer(0));
 | |
|     TreeNode node = getChildAt(0);
 | |
|     int depth = 0;
 | |
|     int current = 1;
 | |
| 
 | |
|     while (! stack.empty())
 | |
|       {
 | |
|         if (node.getChildCount() != 0)
 | |
|           {
 | |
|             node = node.getChildAt(0);
 | |
|             stack.push(new Integer(0));
 | |
|             current++;
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             if (current > depth)
 | |
|               depth = current;
 | |
| 
 | |
|             int size;
 | |
|             int index;
 | |
| 
 | |
|             do
 | |
|               {
 | |
|                 node = node.getParent();
 | |
|                 size = node.getChildCount();
 | |
|                 index = stack.pop().intValue() + 1;
 | |
|                 current--;
 | |
|               }
 | |
|             while (index >= size
 | |
|                    && node != this);
 | |
| 
 | |
|             if (index < size)
 | |
|               {
 | |
|                 node = node.getChildAt(index);
 | |
|                 stack.push(new Integer(index));
 | |
|                 current++;
 | |
|               }
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     return depth;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getLevel
 | |
|    *
 | |
|    * @return int
 | |
|    */
 | |
|   public int getLevel()
 | |
|   {
 | |
|     int count = -1;
 | |
|     TreeNode current = this;
 | |
| 
 | |
|     do
 | |
|       {
 | |
|         current = current.getParent();
 | |
|         count++;
 | |
|       }
 | |
|     while (current != null);
 | |
| 
 | |
|     return count;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getPathToRoot
 | |
|    *
 | |
|    * @param node TODO
 | |
|    * @param depth TODO
 | |
|    *
 | |
|    * @return TreeNode[]
 | |
|    */
 | |
|   protected TreeNode[] getPathToRoot(TreeNode node, int depth)
 | |
|   {
 | |
|     if (node == null)
 | |
|       {
 | |
|         if (depth == 0)
 | |
|           return null;
 | |
| 
 | |
|         return new TreeNode[depth];
 | |
|       }
 | |
| 
 | |
|     TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
 | |
|     path[path.length - depth - 1] = node;
 | |
|     return path;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getUserObjectPath
 | |
|    *
 | |
|    * @return Object[]
 | |
|    */
 | |
|   public Object[] getUserObjectPath()
 | |
|   {
 | |
|     TreeNode[] path = getPathToRoot(this, 0);
 | |
|     Object[] object = new Object[path.length];
 | |
| 
 | |
|     for (int index = 0; index < path.length; ++index)
 | |
|       object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject();
 | |
| 
 | |
|     return object;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the root node by iterating the parents of this node.
 | |
|    *
 | |
|    * @return the root node
 | |
|    */
 | |
|   public TreeNode getRoot()
 | |
|   {
 | |
|     TreeNode current = this;
 | |
|     TreeNode check = current.getParent();
 | |
| 
 | |
|     while (check != null)
 | |
|       {
 | |
|         current = check;
 | |
|         check = current.getParent();
 | |
|       }
 | |
| 
 | |
|     return current;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Tells whether this node is the root node or not.
 | |
|    *
 | |
|    * @return <code>true</code> if this is the root node,
 | |
|    * <code>false</code>otherwise
 | |
|    */
 | |
|   public boolean isRoot()
 | |
|   {
 | |
|     return parent == null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getNextNode
 | |
|    *
 | |
|    * @return DefaultMutableTreeNode
 | |
|    */
 | |
|   public DefaultMutableTreeNode getNextNode()
 | |
|   {
 | |
|     // Return first child.
 | |
|     if (getChildCount() != 0)
 | |
|       return (DefaultMutableTreeNode) getChildAt(0);
 | |
| 
 | |
|     // Return next sibling (if needed the sibling of some parent).
 | |
|     DefaultMutableTreeNode node = this;
 | |
|     DefaultMutableTreeNode sibling;
 | |
| 
 | |
|     do
 | |
|       {
 | |
|         sibling = node.getNextSibling();
 | |
|         node = (DefaultMutableTreeNode) node.getParent();
 | |
|       }
 | |
|     while (sibling == null &&
 | |
|            node != null);
 | |
| 
 | |
|     // Return sibling.
 | |
|     return sibling;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getPreviousNode
 | |
|    *
 | |
|    * @return DefaultMutableTreeNode
 | |
|    */
 | |
|   public DefaultMutableTreeNode getPreviousNode()
 | |
|   {
 | |
|     // Return null if no parent.
 | |
|     if (parent == null)
 | |
|       return null;
 | |
| 
 | |
|     DefaultMutableTreeNode sibling = getPreviousSibling();
 | |
| 
 | |
|     // Return parent if no sibling.
 | |
|     if (sibling == null)
 | |
|       return (DefaultMutableTreeNode) parent;
 | |
| 
 | |
|     // Return last leaf of sibling.
 | |
|     if (sibling.getChildCount() != 0)
 | |
|       return sibling.getLastLeaf();
 | |
| 
 | |
|     // Return sibling.
 | |
|     return sibling;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * preorderEnumeration
 | |
|    *
 | |
|    * @return Enumeration
 | |
|    */
 | |
|   @SuppressWarnings("rawtypes") // Required for API compatibility
 | |
|   public Enumeration preorderEnumeration()
 | |
|   {
 | |
|     return new PreorderEnumeration(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * postorderEnumeration
 | |
|    *
 | |
|    * @return Enumeration
 | |
|    */
 | |
|   @SuppressWarnings("rawtypes") // Required for API compatibility
 | |
|   public Enumeration postorderEnumeration()
 | |
|   {
 | |
|     return new PostorderEnumeration(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * breadthFirstEnumeration
 | |
|    *
 | |
|    * @return Enumeration
 | |
|    */
 | |
|   @SuppressWarnings("rawtypes") // Required for API compatibility
 | |
|   public Enumeration breadthFirstEnumeration()
 | |
|   {
 | |
|     return new BreadthFirstEnumeration(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * depthFirstEnumeration
 | |
|    *
 | |
|    * @return Enumeration
 | |
|    */
 | |
|   @SuppressWarnings("rawtypes") // Required for API compatibility
 | |
|   public Enumeration depthFirstEnumeration()
 | |
|   {
 | |
|     return postorderEnumeration();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * pathFromAncestorEnumeration
 | |
|    *
 | |
|    * @param node TODO
 | |
|    *
 | |
|    * @return Enumeration
 | |
|    */
 | |
|   @SuppressWarnings("rawtypes") // Required for API compatibility
 | |
|   public Enumeration pathFromAncestorEnumeration(TreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     TreeNode parent = this;
 | |
|     Vector<TreeNode> nodes = new Vector<TreeNode>();
 | |
|     nodes.add(this);
 | |
| 
 | |
|     while (parent != node && parent != null)
 | |
|       {
 | |
|         parent = parent.getParent();
 | |
|         nodes.add(0, parent);
 | |
|       }
 | |
| 
 | |
|     if (parent != node)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     return nodes.elements();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if <code>node</code> is a child of this tree
 | |
|    * node, and <code>false</code> otherwise.  If <code>node</code> is
 | |
|    * <code>null</code>, this method returns <code>false</code>.
 | |
|    *
 | |
|    * @param node  the node (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return A boolean.
 | |
|    */
 | |
|   public boolean isNodeChild(TreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       return false;
 | |
| 
 | |
|     return node.getParent() == this;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the first child node belonging to this tree node.
 | |
|    *
 | |
|    * @return The first child node.
 | |
|    *
 | |
|    * @throws NoSuchElementException if this tree node has no children.
 | |
|    */
 | |
|   public TreeNode getFirstChild()
 | |
|   {
 | |
|     return children.firstElement();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the last child node belonging to this tree node.
 | |
|    *
 | |
|    * @return The last child node.
 | |
|    *
 | |
|    * @throws NoSuchElementException if this tree node has no children.
 | |
|    */
 | |
|   public TreeNode getLastChild()
 | |
|   {
 | |
|     return children.lastElement();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the next child after the specified <code>node</code>, or
 | |
|    * <code>null</code> if there is no child after the specified
 | |
|    * <code>node</code>.
 | |
|    *
 | |
|    * @param node  a child of this node (<code>null</code> not permitted).
 | |
|    *
 | |
|    * @return The next child, or <code>null</code>.
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>node</code> is not a child of
 | |
|    *     this node, or is <code>null</code>.
 | |
|    */
 | |
|   public TreeNode getChildAfter(TreeNode node)
 | |
|   {
 | |
|     if (node == null || node.getParent() != this)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     int index = getIndex(node) + 1;
 | |
| 
 | |
|     if (index == getChildCount())
 | |
|       return null;
 | |
| 
 | |
|     return getChildAt(index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the previous child before the specified <code>node</code>, or
 | |
|    * <code>null</code> if there is no child before the specified
 | |
|    * <code>node</code>.
 | |
|    *
 | |
|    * @param node  a child of this node (<code>null</code> not permitted).
 | |
|    *
 | |
|    * @return The previous child, or <code>null</code>.
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>node</code> is not a child of
 | |
|    *     this node, or is <code>null</code>.
 | |
|    */
 | |
|   public TreeNode getChildBefore(TreeNode node)
 | |
|   {
 | |
|     if (node == null || node.getParent() != this)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     int index = getIndex(node) - 1;
 | |
| 
 | |
|     if (index < 0)
 | |
|       return null;
 | |
| 
 | |
|     return getChildAt(index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if this tree node and <code>node</code> share
 | |
|    * the same parent.  If <code>node</code> is this tree node, the method
 | |
|    * returns <code>true</code> and if <code>node</code> is <code>null</code>
 | |
|    * this method returns <code>false</code>.
 | |
|    *
 | |
|    * @param node  the node (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return A boolean.
 | |
|    */
 | |
|   public boolean isNodeSibling(TreeNode node)
 | |
|   {
 | |
|     if (node == null)
 | |
|       return false;
 | |
|     if (node == this)
 | |
|       return true;
 | |
|     return node.getParent() == getParent() && getParent() != null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the number of siblings for this tree node.  If the tree node has
 | |
|    * a parent, this method returns the child count for the parent, otherwise
 | |
|    * it returns <code>1</code>.
 | |
|    *
 | |
|    * @return The sibling count.
 | |
|    */
 | |
|   public int getSiblingCount()
 | |
|   {
 | |
|     if (parent == null)
 | |
|       return 1;
 | |
| 
 | |
|     return parent.getChildCount();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the next sibling for this tree node.  If this node has no parent,
 | |
|    * or this node is the last child of its parent, this method returns
 | |
|    * <code>null</code>.
 | |
|    *
 | |
|    * @return The next sibling, or <code>null</code>.
 | |
|    */
 | |
|   public DefaultMutableTreeNode getNextSibling()
 | |
|   {
 | |
|     if (parent == null)
 | |
|       return null;
 | |
| 
 | |
|     int index = parent.getIndex(this) + 1;
 | |
| 
 | |
|     if (index == parent.getChildCount())
 | |
|       return null;
 | |
| 
 | |
|     return (DefaultMutableTreeNode) parent.getChildAt(index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the previous sibling for this tree node.  If this node has no
 | |
|    * parent, or this node is the first child of its parent, this method returns
 | |
|    * <code>null</code>.
 | |
|    *
 | |
|    * @return The previous sibling, or <code>null</code>.
 | |
|    */
 | |
|   public DefaultMutableTreeNode getPreviousSibling()
 | |
|   {
 | |
|     if (parent == null)
 | |
|       return null;
 | |
| 
 | |
|     int index = parent.getIndex(this) - 1;
 | |
| 
 | |
|     if (index < 0)
 | |
|       return null;
 | |
| 
 | |
|     return (DefaultMutableTreeNode) parent.getChildAt(index);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if this tree node is a lead node (that is, it
 | |
|    * has no children), and <code>false</otherwise>.
 | |
|    *
 | |
|    * @return A boolean.
 | |
|    */
 | |
|   public boolean isLeaf()
 | |
|   {
 | |
|     return children.size() == 0;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the first leaf node that is a descendant of this node.  Recall
 | |
|    * that a node is its own descendant, so if this node has no children then
 | |
|    * it is returned as the first leaf.
 | |
|    *
 | |
|    * @return The first leaf node.
 | |
|    */
 | |
|   public DefaultMutableTreeNode getFirstLeaf()
 | |
|   {
 | |
|     TreeNode current = this;
 | |
| 
 | |
|     while (current.getChildCount() > 0)
 | |
|       current = current.getChildAt(0);
 | |
| 
 | |
|     return (DefaultMutableTreeNode) current;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the last leaf node that is a descendant of this node.  Recall
 | |
|    * that a node is its own descendant, so if this node has no children then
 | |
|    * it is returned as the last leaf.
 | |
|    *
 | |
|    * @return The first leaf node.
 | |
|    */
 | |
|   public DefaultMutableTreeNode getLastLeaf()
 | |
|   {
 | |
|     TreeNode current = this;
 | |
|     int size = current.getChildCount();
 | |
| 
 | |
|     while (size > 0)
 | |
|       {
 | |
|         current = current.getChildAt(size - 1);
 | |
|         size = current.getChildCount();
 | |
|       }
 | |
| 
 | |
|     return (DefaultMutableTreeNode) current;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the next leaf node after this tree node.
 | |
|    *
 | |
|    * @return The next leaf node, or <code>null</code>.
 | |
|    */
 | |
|   public DefaultMutableTreeNode getNextLeaf()
 | |
|   {
 | |
|     // if there is a next sibling, return its first leaf
 | |
|     DefaultMutableTreeNode sibling = getNextSibling();
 | |
|     if (sibling != null)
 | |
|       return sibling.getFirstLeaf();
 | |
|     // otherwise move up one level and try again...
 | |
|     if (parent != null)
 | |
|       return ((DefaultMutableTreeNode) parent).getNextLeaf();
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the previous leaf node before this tree node.
 | |
|    *
 | |
|    * @return The previous leaf node, or <code>null</code>.
 | |
|    */
 | |
|   public DefaultMutableTreeNode getPreviousLeaf()
 | |
|   {
 | |
|     // if there is a previous sibling, return its last leaf
 | |
|     DefaultMutableTreeNode sibling = getPreviousSibling();
 | |
|     if (sibling != null)
 | |
|       return sibling.getLastLeaf();
 | |
|     // otherwise move up one level and try again...
 | |
|     if (parent != null)
 | |
|       return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * getLeafCount
 | |
|    *
 | |
|    * @return int
 | |
|    */
 | |
|   public int getLeafCount()
 | |
|   {
 | |
|     int count = 0;
 | |
|     Enumeration<?> e = depthFirstEnumeration();
 | |
| 
 | |
|     while (e.hasMoreElements())
 | |
|       {
 | |
|         TreeNode current = (TreeNode) e.nextElement();
 | |
| 
 | |
|         if (current.isLeaf())
 | |
|           count++;
 | |
|       }
 | |
| 
 | |
|     return count;
 | |
|   }
 | |
| 
 | |
|   /** Provides an enumeration of a tree in breadth-first traversal
 | |
|    * order.
 | |
|    */
 | |
|   static class BreadthFirstEnumeration implements Enumeration<TreeNode>
 | |
|   {
 | |
| 
 | |
|       LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
 | |
| 
 | |
|       BreadthFirstEnumeration(TreeNode node)
 | |
|       {
 | |
|           queue.add(node);
 | |
|       }
 | |
| 
 | |
|       public boolean hasMoreElements()
 | |
|       {
 | |
|           return !queue.isEmpty();
 | |
|       }
 | |
| 
 | |
|       public TreeNode nextElement()
 | |
|       {
 | |
|           if (queue.isEmpty())
 | |
|               throw new NoSuchElementException("No more elements left.");
 | |
| 
 | |
|           TreeNode node = queue.removeFirst();
 | |
| 
 | |
| 	  @SuppressWarnings("unchecked")
 | |
|           Enumeration<TreeNode> children =
 | |
|             (Enumeration<TreeNode>) node.children();
 | |
|           while (children.hasMoreElements())
 | |
|               queue.add(children.nextElement());
 | |
| 
 | |
|           return node;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /** Provides an enumeration of a tree traversing it
 | |
|    * preordered.
 | |
|    */
 | |
|   static class PreorderEnumeration implements Enumeration<TreeNode>
 | |
|   {
 | |
|           TreeNode next;
 | |
| 
 | |
|       Stack<Enumeration<TreeNode>> childrenEnums =
 | |
|         new Stack<Enumeration<TreeNode>>();
 | |
| 
 | |
|       PreorderEnumeration(TreeNode node)
 | |
|       {
 | |
|           next = node;
 | |
| 	  @SuppressWarnings("unchecked")
 | |
| 	      Enumeration<TreeNode> children =
 | |
| 	      (Enumeration<TreeNode>) node.children();
 | |
|           childrenEnums.push(children);
 | |
|       }
 | |
| 
 | |
|       public boolean hasMoreElements()
 | |
|       {
 | |
|           return next != null;
 | |
|       }
 | |
| 
 | |
|       public TreeNode nextElement()
 | |
|       {
 | |
|           if (next == null)
 | |
|               throw new NoSuchElementException("No more elements left.");
 | |
| 
 | |
|           TreeNode current = next;
 | |
| 
 | |
|           Enumeration<TreeNode> children = childrenEnums.peek();
 | |
| 
 | |
|           // Retrieves the next element.
 | |
|           next = traverse(children);
 | |
| 
 | |
|           return current;
 | |
|       }
 | |
| 
 | |
|       private TreeNode traverse(Enumeration<TreeNode> children)
 | |
|       {
 | |
|           // If more children are available step down.
 | |
|           if (children.hasMoreElements())
 | |
|           {
 | |
|               TreeNode child = children.nextElement();
 | |
| 	      @SuppressWarnings("unchecked")
 | |
| 		  Enumeration<TreeNode> grandchildren =
 | |
| 		  (Enumeration<TreeNode>) child.children();
 | |
|               childrenEnums.push(grandchildren);
 | |
| 
 | |
|               return child;
 | |
|           }
 | |
| 
 | |
|           // If no children are left, we return to a higher level.
 | |
|           childrenEnums.pop();
 | |
| 
 | |
|           // If there are no more levels left, there is no next
 | |
|           // element to return.
 | |
|           if (childrenEnums.isEmpty())
 | |
|               return null;
 | |
|           else
 | |
|           {
 | |
|               return traverse(childrenEnums.peek());
 | |
|           }
 | |
|       }
 | |
|    }
 | |
| 
 | |
|   /** Provides an enumeration of a tree traversing it
 | |
|    * postordered (= depth-first).
 | |
|    */
 | |
|    static class PostorderEnumeration implements Enumeration<TreeNode>
 | |
|    {
 | |
| 
 | |
|        Stack<TreeNode> nodes = new Stack<TreeNode>();
 | |
|        Stack<Enumeration<TreeNode>> childrenEnums =
 | |
|          new Stack<Enumeration<TreeNode>>();
 | |
| 
 | |
|        PostorderEnumeration(TreeNode node)
 | |
|        {
 | |
|            nodes.push(node);
 | |
| 	   @SuppressWarnings("unchecked")
 | |
| 	       Enumeration<TreeNode> children =
 | |
| 	       (Enumeration<TreeNode>) node.children();
 | |
|            childrenEnums.push(children);
 | |
|        }
 | |
| 
 | |
|        public boolean hasMoreElements()
 | |
|        {
 | |
|            return !nodes.isEmpty();
 | |
|        }
 | |
| 
 | |
|        public TreeNode nextElement()
 | |
|        {
 | |
|            if (nodes.isEmpty())
 | |
|                throw new NoSuchElementException("No more elements left!");
 | |
| 
 | |
|            Enumeration<TreeNode> children = childrenEnums.peek();
 | |
| 
 | |
|            return traverse(children);
 | |
|        }
 | |
| 
 | |
|        private TreeNode traverse(Enumeration<TreeNode> children)
 | |
|        {
 | |
|            if (children.hasMoreElements())
 | |
|            {
 | |
|                TreeNode node = children.nextElement();
 | |
|                nodes.push(node);
 | |
| 
 | |
| 	       @SuppressWarnings("unchecked")
 | |
| 		   Enumeration<TreeNode> newChildren =
 | |
| 		   (Enumeration<TreeNode>) node.children();
 | |
|                childrenEnums.push(newChildren);
 | |
| 
 | |
|                return traverse(newChildren);
 | |
|            }
 | |
|            else
 | |
|            {
 | |
|                childrenEnums.pop();
 | |
| 
 | |
|                // Returns the node whose children
 | |
|                // have all been visited. (= postorder)
 | |
|                TreeNode next = nodes.peek();
 | |
|                nodes.pop();
 | |
| 
 | |
|                return next;
 | |
|            }
 | |
|        }
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 |