- /*
 - * @(#)DefaultTreeModel.java 1.41 00/02/02
 - *
 - * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
 - *
 - * This software is the proprietary information of Sun Microsystems, Inc.
 - * Use is subject to license terms.
 - *
 - */
 - package javax.swing.tree;
 - import java.util.*;
 - import java.awt.*;
 - import java.io.*;
 - import javax.swing.event.*;
 - /**
 - * A simple tree data model that uses TreeNodes.
 - * For further information and examples that use DefaultTreeModel,
 - * see <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html">How to Use Trees</a>
 - * in <em>The Java Tutorial.</em>
 - * <p>
 - * <strong>Warning:</strong>
 - * Serialized objects of this class will not be compatible with
 - * future Swing releases. The current serialization support is appropriate
 - * for short term storage or RMI between applications running the same
 - * version of Swing. A future release of Swing will provide support for
 - * long term persistence.
 - *
 - * @version 1.41 02/02/00
 - * @author Rob Davis
 - * @author Ray Ryan
 - * @author Scott Violet
 - */
 - public class DefaultTreeModel implements Serializable, TreeModel {
 - /** Root of the tree. */
 - protected TreeNode root;
 - /** Listeners. */
 - protected EventListenerList listenerList = new EventListenerList();
 - /**
 - * Determines how the <code>isLeaf</code> method figures
 - * out if a node is a leaf node. If true, a node is a leaf
 - * node if it does not allow children. (If it allows
 - * children, it is not a leaf node, even if no children
 - * are present.) That lets you distinguish between <i>folder</i>
 - * nodes and <i>file</i> nodes in a file system, for example.
 - * <p>
 - * If this value is false, then any node which has no
 - * children is a leaf node, and any node may acquire
 - * children.
 - *
 - * @see TreeNode#getAllowsChildren
 - * @see TreeModel#isLeaf
 - * @see #setAsksAllowsChildren
 - */
 - protected boolean asksAllowsChildren;
 - /**
 - * Creates a tree in which any node can have children.
 - *
 - * @param root a TreeNode object that is the root of the tree
 - * @see #DefaultTreeModel(TreeNode, boolean)
 - */
 - public DefaultTreeModel(TreeNode root) {
 - this(root, false);
 - }
 - /**
 - * Creates a tree specifying whether any node can have children,
 - * or whether only certain nodes can have children.
 - *
 - * @param root a TreeNode object that is the root of the tree
 - * @param askAllowsChildren a boolean, false if any node can
 - * have children, true if each node is asked to see if
 - * it can have children
 - * @see #asksAllowsChildren
 - */
 - public DefaultTreeModel(TreeNode root, boolean asksAllowsChildren) {
 - super();
 - if (root == null) {
 - throw new IllegalArgumentException("root is null");
 - }
 - this.root = root;
 - this.asksAllowsChildren = asksAllowsChildren;
 - }
 - /**
 - * Sets whether or not to test leafness by asking getAllowsChildren()
 - * or isLeaf() to the TreeNodes. If newvalue is true, getAllowsChildren()
 - * is messaged, otherwise isLeaf() is messaged.
 - */
 - public void setAsksAllowsChildren(boolean newValue) {
 - asksAllowsChildren = newValue;
 - }
 - /**
 - * Tells how leaf nodes are determined.
 - *
 - * @return true if only nodes which do not allow children are
 - * leaf nodes, false if nodes which have no children
 - * (even if allowed) are leaf nodes
 - * @see #asksAllowsChildren
 - */
 - public boolean asksAllowsChildren() {
 - return asksAllowsChildren;
 - }
 - /**
 - * Sets the root to <code>root</code>. This will throw an
 - * IllegalArgumentException if <code>root</code> is null.
 - */
 - public void setRoot(TreeNode root) {
 - if(root == null)
 - throw new IllegalArgumentException("Root of tree is not allowed to be null");
 - this.root = root;
 - nodeStructureChanged(root);
 - }
 - /**
 - * Returns the root of the tree. Returns null only if the tree has
 - * no nodes.
 - *
 - * @return the root of the tree
 - */
 - public Object getRoot() {
 - return root;
 - }
 - /**
 - * Returns the index of child in parent.
 - */
 - public int getIndexOfChild(Object parent, Object child) {
 - if(parent == null || child == null)
 - return -1;
 - return ((TreeNode)parent).getIndex((TreeNode)child);
 - }
 - /**
 - * Returns the child of <I>parent</I> at index <I>index</I> in the parent's
 - * child array. <I>parent</I> must be a node previously obtained from
 - * this data source. This should not return null if <i>index</i>
 - * is a valid index for <i>parent</i> (that is <i>index</i> >= 0 &&
 - * <i>index</i> < getChildCount(<i>parent</i>)).
 - *
 - * @param parent a node in the tree, obtained from this data source
 - * @return the child of <I>parent</I> at index <I>index</I>
 - */
 - public Object getChild(Object parent, int index) {
 - return ((TreeNode)parent).getChildAt(index);
 - }
 - /**
 - * Returns the number of children of <I>parent</I>. Returns 0 if the node
 - * is a leaf or if it has no children. <I>parent</I> must be a node
 - * previously obtained from this data source.
 - *
 - * @param parent a node in the tree, obtained from this data source
 - * @return the number of children of the node <I>parent</I>
 - */
 - public int getChildCount(Object parent) {
 - return ((TreeNode)parent).getChildCount();
 - }
 - /**
 - * Returns whether the specified node is a leaf node.
 - * The way the test is performed depends on the
 - * <code>askAllowsChildren</code> setting.
 - *
 - * @param node the node to check
 - * @return true if the node is a leaf node
 - *
 - * @see #asksAllowsChildren
 - * @see TreeModel#isLeaf
 - */
 - public boolean isLeaf(Object node) {
 - if(asksAllowsChildren)
 - return !((TreeNode)node).getAllowsChildren();
 - return ((TreeNode)node).isLeaf();
 - }
 - /**
 - * Invoke this method if you've modified the TreeNodes upon which this
 - * model depends. The model will notify all of its listeners that the
 - * model has changed.
 - */
 - public void reload() {
 - reload(root);
 - }
 - /**
 - * This sets the user object of the TreeNode identified by path
 - * and posts a node changed. If you use custom user objects in
 - * the TreeModel you're going to need to subclass this and
 - * set the user object of the changed node to something meaningful.
 - */
 - public void valueForPathChanged(TreePath path, Object newValue) {
 - MutableTreeNode aNode = (MutableTreeNode)path.getLastPathComponent();
 - aNode.setUserObject(newValue);
 - nodeChanged(aNode);
 - }
 - /**
 - * Invoked this to insert newChild at location index in parents children.
 - * This will then message nodesWereInserted to create the appropriate
 - * event. This is the preferred way to add children as it will create
 - * the appropriate event.
 - */
 - public void insertNodeInto(MutableTreeNode newChild,
 - MutableTreeNode parent, int index){
 - parent.insert(newChild, index);
 - int[] newIndexs = new int[1];
 - newIndexs[0] = index;
 - nodesWereInserted(parent, newIndexs);
 - }
 - /**
 - * Message this to remove node from its parent. This will message
 - * nodesWereRemoved to create the appropriate event. This is the
 - * preferred way to remove a node as it handles the event creation
 - * for you.
 - */
 - public void removeNodeFromParent(MutableTreeNode node) {
 - MutableTreeNode parent = (MutableTreeNode)node.getParent();
 - if(parent == null)
 - throw new IllegalArgumentException("node does not have a parent.");
 - int[] childIndex = new int[1];
 - Object[] removedArray = new Object[1];
 - childIndex[0] = parent.getIndex(node);
 - parent.remove(childIndex[0]);
 - removedArray[0] = node;
 - nodesWereRemoved(parent, childIndex, removedArray);
 - }
 - /**
 - * Invoke this method after you've changed how node is to be
 - * represented in the tree.
 - */
 - public void nodeChanged(TreeNode node) {
 - if(listenerList != null && node != null) {
 - TreeNode parent = node.getParent();
 - if(parent != null) {
 - int anIndex = parent.getIndex(node);
 - if(anIndex != -1) {
 - int[] cIndexs = new int[1];
 - cIndexs[0] = anIndex;
 - nodesChanged(parent, cIndexs);
 - }
 - }
 - else if (node == getRoot()) {
 - nodesChanged(node, null);
 - }
 - }
 - }
 - /**
 - * Invoke this method if you've modified the TreeNodes upon which this
 - * model depends. The model will notify all of its listeners that the
 - * model has changed below the node <code>node</code> (PENDING).
 - */
 - public void reload(TreeNode node) {
 - if(node != null) {
 - fireTreeStructureChanged(this, getPathToRoot(node), null, null);
 - }
 - }
 - /**
 - * Invoke this method after you've inserted some TreeNodes into
 - * node. childIndices should be the index of the new elements and
 - * must be sorted in ascending order.
 - */
 - public void nodesWereInserted(TreeNode node, int[] childIndices) {
 - if(listenerList != null && node != null && childIndices != null
 - && childIndices.length > 0) {
 - int cCount = childIndices.length;
 - Object[] newChildren = new Object[cCount];
 - for(int counter = 0; counter < cCount; counter++)
 - newChildren[counter] = node.getChildAt(childIndices[counter]);
 - fireTreeNodesInserted(this, getPathToRoot(node), childIndices,
 - newChildren);
 - }
 - }
 - /**
 - * Invoke this method after you've removed some TreeNodes from
 - * node. childIndices should be the index of the removed elements and
 - * must be sorted in ascending order. And removedChildren should be
 - * the array of the children objects that were removed.
 - */
 - public void nodesWereRemoved(TreeNode node, int[] childIndices,
 - Object[] removedChildren) {
 - if(node != null && childIndices != null) {
 - fireTreeNodesRemoved(this, getPathToRoot(node), childIndices,
 - removedChildren);
 - }
 - }
 - /**
 - * Invoke this method after you've changed how the children identified by
 - * childIndicies are to be represented in the tree.
 - */
 - public void nodesChanged(TreeNode node, int[] childIndices) {
 - if(node != null) {
 - if (childIndices != null) {
 - int cCount = childIndices.length;
 - if(cCount > 0) {
 - Object[] cChildren = new Object[cCount];
 - for(int counter = 0; counter < cCount; counter++)
 - cChildren[counter] = node.getChildAt
 - (childIndices[counter]);
 - fireTreeNodesChanged(this, getPathToRoot(node),
 - childIndices, cChildren);
 - }
 - }
 - else if (node == getRoot()) {
 - fireTreeNodesChanged(this, getPathToRoot(node), null, null);
 - }
 - }
 - }
 - /**
 - * Invoke this method if you've totally changed the children of
 - * node and its childrens children... This will post a
 - * treeStructureChanged event.
 - */
 - public void nodeStructureChanged(TreeNode node) {
 - if(node != null) {
 - fireTreeStructureChanged(this, getPathToRoot(node), null, null);
 - }
 - }
 - /**
 - * Builds the parents of node up to and including the root node,
 - * where the original node is the last element in the returned array.
 - * The length of the returned array gives the node's depth in the
 - * tree.
 - *
 - * @param aNode the TreeNode to get the path for
 - * @param an array of TreeNodes giving the path from the root to the
 - * specified node.
 - */
 - public TreeNode[] getPathToRoot(TreeNode aNode) {
 - return getPathToRoot(aNode, 0);
 - }
 - /**
 - * Builds the parents of node up to and including the root node,
 - * where the original node is the last element in the returned array.
 - * The length of the returned array gives the node's depth in the
 - * tree.
 - *
 - * @param aNode the TreeNode to get the path for
 - * @param depth an int giving the number of steps already taken towards
 - * the root (on recursive calls), used to size the returned array
 - * @return an array of TreeNodes giving the path from the root to the
 - * specified node
 - */
 - protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) {
 - TreeNode[] retNodes;
 - // This method recurses, traversing towards the root in order
 - // size the array. On the way back, it fills in the nodes,
 - // starting from the root and working back to the original node.
 - /* Check for null, in case someone passed in a null node, or
 - they passed in an element that isn't rooted at root. */
 - if(aNode == null) {
 - if(depth == 0)
 - return null;
 - else
 - retNodes = new TreeNode[depth];
 - }
 - else {
 - depth++;
 - if(aNode == root)
 - retNodes = new TreeNode[depth];
 - else
 - retNodes = getPathToRoot(aNode.getParent(), depth);
 - retNodes[retNodes.length - depth] = aNode;
 - }
 - return retNodes;
 - }
 - //
 - // Events
 - //
 - /**
 - * Adds a listener for the TreeModelEvent posted after the tree changes.
 - *
 - * @see #removeTreeModelListener
 - * @param l the listener to add
 - */
 - public void addTreeModelListener(TreeModelListener l) {
 - listenerList.add(TreeModelListener.class, l);
 - }
 - /**
 - * Removes a listener previously added with <B>addTreeModelListener()</B>.
 - *
 - * @see #addTreeModelListener
 - * @param l the listener to remove
 - */
 - public void removeTreeModelListener(TreeModelListener l) {
 - listenerList.remove(TreeModelListener.class, l);
 - }
 - /*
 - * Notify all listeners that have registered interest for
 - * notification on this event type. The event instance
 - * is lazily created using the parameters passed into
 - * the fire method.
 - * @see EventListenerList
 - */
 - protected void fireTreeNodesChanged(Object source, Object[] path,
 - int[] childIndices,
 - Object[] children) {
 - // Guaranteed to return a non-null array
 - Object[] listeners = listenerList.getListenerList();
 - TreeModelEvent e = null;
 - // Process the listeners last to first, notifying
 - // those that are interested in this event
 - for (int i = listeners.length-2; i>=0; i-=2) {
 - if (listeners[i]==TreeModelListener.class) {
 - // Lazily create the event:
 - if (e == null)
 - e = new TreeModelEvent(source, path,
 - childIndices, children);
 - ((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
 - }
 - }
 - }
 - /*
 - * Notify all listeners that have registered interest for
 - * notification on this event type. The event instance
 - * is lazily created using the parameters passed into
 - * the fire method.
 - * @see EventListenerList
 - */
 - protected void fireTreeNodesInserted(Object source, Object[] path,
 - int[] childIndices,
 - Object[] children) {
 - // Guaranteed to return a non-null array
 - Object[] listeners = listenerList.getListenerList();
 - TreeModelEvent e = null;
 - // Process the listeners last to first, notifying
 - // those that are interested in this event
 - for (int i = listeners.length-2; i>=0; i-=2) {
 - if (listeners[i]==TreeModelListener.class) {
 - // Lazily create the event:
 - if (e == null)
 - e = new TreeModelEvent(source, path,
 - childIndices, children);
 - ((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
 - }
 - }
 - }
 - /*
 - * Notify all listeners that have registered interest for
 - * notification on this event type. The event instance
 - * is lazily created using the parameters passed into
 - * the fire method.
 - * @see EventListenerList
 - */
 - protected void fireTreeNodesRemoved(Object source, Object[] path,
 - int[] childIndices,
 - Object[] children) {
 - // Guaranteed to return a non-null array
 - Object[] listeners = listenerList.getListenerList();
 - TreeModelEvent e = null;
 - // Process the listeners last to first, notifying
 - // those that are interested in this event
 - for (int i = listeners.length-2; i>=0; i-=2) {
 - if (listeners[i]==TreeModelListener.class) {
 - // Lazily create the event:
 - if (e == null)
 - e = new TreeModelEvent(source, path,
 - childIndices, children);
 - ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
 - }
 - }
 - }
 - /*
 - * Notify all listeners that have registered interest for
 - * notification on this event type. The event instance
 - * is lazily created using the parameters passed into
 - * the fire method.
 - * @see EventListenerList
 - */
 - protected void fireTreeStructureChanged(Object source, Object[] path,
 - int[] childIndices,
 - Object[] children) {
 - // Guaranteed to return a non-null array
 - Object[] listeners = listenerList.getListenerList();
 - TreeModelEvent e = null;
 - // Process the listeners last to first, notifying
 - // those that are interested in this event
 - for (int i = listeners.length-2; i>=0; i-=2) {
 - if (listeners[i]==TreeModelListener.class) {
 - // Lazily create the event:
 - if (e == null)
 - e = new TreeModelEvent(source, path,
 - childIndices, children);
 - ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
 - }
 - }
 - }
 - /**
 - * Return an array of all the listeners of the given type that
 - * were added to this model.
 - *
 - * @returns all of the objects recieving <em>listenerType</em> notifications
 - * from this model
 - *
 - * @since 1.3
 - */
 - public EventListener[] getListeners(Class listenerType) {
 - return listenerList.getListeners(listenerType);
 - }
 - // Serialization support.
 - private void writeObject(ObjectOutputStream s) throws IOException {
 - Vector values = new Vector();
 - s.defaultWriteObject();
 - // Save the root, if its Serializable.
 - if(root != null && root instanceof Serializable) {
 - values.addElement("root");
 - values.addElement(root);
 - }
 - s.writeObject(values);
 - }
 - private void readObject(ObjectInputStream s)
 - throws IOException, ClassNotFoundException {
 - s.defaultReadObject();
 - Vector values = (Vector)s.readObject();
 - int indexCounter = 0;
 - int maxCounter = values.size();
 - if(indexCounter < maxCounter && values.elementAt(indexCounter).
 - equals("root")) {
 - root = (TreeNode)values.elementAt(++indexCounter);
 - indexCounter++;
 - }
 - }
 - } // End of class DefaultTreeModel