home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
VCAFE.3.0A
/
Main.bin
/
DefaultTreeModel.java
< prev
next >
Wrap
Text File
|
1998-11-09
|
18KB
|
486 lines
/*
* @(#)DefaultTreeModel.java 1.29 98/04/02
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package javax.awt.swing.tree;
import java.util.*;
import java.awt.*;
import java.io.*;
import javax.awt.swing.event.TreeModelEvent;
import javax.awt.swing.event.TreeModelListener;
import javax.awt.swing.event.EventListenerList;
/**
* A simple tree data model that uses TreeNodes.
* <p>
* Warning: 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 Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*
* @version 1.29 04/02/98
* @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> determines 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.) If this value is false, then any node
* which has no children is a leaf node.
*
* @see TreeNode#getAllowsChildren
* @see TreeModel#isLeaf
* @see #setAsksAllowsChildren
*/
protected boolean asksAllowsChildren;
public DefaultTreeModel(TreeNode root) {
this(root, false);
}
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;
}
public Object getRoot() {
return root;
}
public int getIndexOfChild(Object parent, Object child) {
if(parent == null || child == null)
return 0;
return ((TreeNode)parent).getIndex((TreeNode)child);
}
public Object getChild(Object parent, int index) {
return ((TreeNode)parent).getChildAt(index);
}
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) {
Object[] aPath = path.getPath();
MutableTreeNode aNode = (MutableTreeNode)aPath[aPath.length - 1];
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);
}
}
}
}
/**
* 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 && 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);
}
}
}
/**
* 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
//
public void addTreeModelListener(TreeModelListener l) {
listenerList.add(TreeModelListener.class, l);
}
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);
}
}
}
// Serialization support.
private void writeObject(ObjectOutputStream s) throws IOException {
Vector values = new Vector();
s.defaultWriteObject();
// Save the cellRenderer, 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