/* | 
|
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code 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 | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package javax.swing.tree;  | 
|
import java.util.*;  | 
|
import java.beans.ConstructorProperties;  | 
|
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="https://docs.oracle.com/javase/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.  As of 1.4, support for long term storage | 
|
 * of all JavaBeans™ | 
|
 * has been added to the <code>java.beans</code> package. | 
|
 * Please see {@link java.beans.XMLEncoder}. | 
|
 * | 
|
 * @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) | 
|
*/  | 
|
     @ConstructorProperties({"root"}) | 
|
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 asksAllowsChildren 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();  | 
|
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>. A null <code>root</code> implies | 
|
     * the tree is to display nothing, and is legal. | 
|
*/  | 
|
public void setRoot(TreeNode root) {  | 
|
Object oldRoot = this.root;  | 
|
this.root = root;  | 
|
if (root == null && oldRoot != null) {  | 
|
fireTreeStructureChanged(this, null);  | 
|
}  | 
|
        else { | 
|
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. | 
|
     * If either the parent or child is <code>null</code>, returns -1. | 
|
     * @param parent a note in the tree, obtained from this data source | 
|
     * @param child the node we are interested in | 
|
     * @return the index of the child in the parent, or -1 | 
|
     *    if either the parent or the child is <code>null</code> | 
|
*/  | 
|
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 {@code TreeNode}s 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 {@code TreeNode}s upon which | 
|
     * this model depends. The model will notify all of its listeners that the | 
|
     * model has changed below the given node. | 
|
     * | 
|
     * @param node the node below which the model has changed | 
|
*/  | 
|
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 children's 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 | 
|
*/  | 
|
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);  | 
|
}  | 
|
    /** | 
|
     * Returns an array of all the tree model listeners | 
|
     * registered on this model. | 
|
     * | 
|
     * @return all of this model's <code>TreeModelListener</code>s | 
|
     *         or an empty | 
|
     *         array if no tree model listeners are currently registered | 
|
     * | 
|
     * @see #addTreeModelListener | 
|
     * @see #removeTreeModelListener | 
|
     * | 
|
     * @since 1.4 | 
|
*/  | 
|
public TreeModelListener[] getTreeModelListeners() {  | 
|
return listenerList.getListeners(TreeModelListener.class);  | 
|
}  | 
|
    /** | 
|
     * Notifies 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. | 
|
     * | 
|
     * @param source the source of the {@code TreeModelEvent}; | 
|
     *               typically {@code this} | 
|
     * @param path the path to the parent of the nodes that changed; use | 
|
     *             {@code null} to identify the root has changed | 
|
     * @param childIndices the indices of the changed elements | 
|
     * @param children the changed elements | 
|
*/  | 
|
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);  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Notifies 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. | 
|
     * | 
|
     * @param source the source of the {@code TreeModelEvent}; | 
|
     *               typically {@code this} | 
|
     * @param path the path to the parent the nodes were added to | 
|
     * @param childIndices the indices of the new elements | 
|
     * @param children the new elements | 
|
*/  | 
|
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);  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Notifies 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. | 
|
     * | 
|
     * @param source the source of the {@code TreeModelEvent}; | 
|
     *               typically {@code this} | 
|
     * @param path the path to the parent the nodes were removed from | 
|
     * @param childIndices the indices of the removed elements | 
|
     * @param children the removed elements | 
|
*/  | 
|
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);  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Notifies 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. | 
|
     * | 
|
     * @param source the source of the {@code TreeModelEvent}; | 
|
     *               typically {@code this} | 
|
     * @param path the path to the parent of the structure that has changed; | 
|
     *             use {@code null} to identify the root has changed | 
|
     * @param childIndices the indices of the affected elements | 
|
     * @param children the affected elements | 
|
*/  | 
|
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);  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Notifies 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. | 
|
     * | 
|
     * @param source the source of the {@code TreeModelEvent}; | 
|
     *               typically {@code this} | 
|
     * @param path the path to the parent of the structure that has changed; | 
|
     *             use {@code null} to identify the root has changed | 
|
*/  | 
|
private void fireTreeStructureChanged(Object source, TreePath path) {  | 
|
        // 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);  | 
|
((TreeModelListener)listeners[i+1]).treeStructureChanged(e);  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an array of all the objects currently registered | 
|
     * as <code><em>Foo</em>Listener</code>s | 
|
     * upon this model. | 
|
     * <code><em>Foo</em>Listener</code>s are registered using the | 
|
     * <code>add<em>Foo</em>Listener</code> method. | 
|
     * | 
|
     * <p> | 
|
     * | 
|
     * You can specify the <code>listenerType</code> argument | 
|
     * with a class literal, | 
|
     * such as | 
|
     * <code><em>Foo</em>Listener.class</code>. | 
|
     * For example, you can query a | 
|
     * <code>DefaultTreeModel</code> <code>m</code> | 
|
     * for its tree model listeners with the following code: | 
|
     * | 
|
     * <pre>TreeModelListener[] tmls = (TreeModelListener[])(m.getListeners(TreeModelListener.class));</pre> | 
|
     * | 
|
     * If no such listeners exist, this method returns an empty array. | 
|
     * | 
|
     * @param listenerType the type of listeners requested; this parameter | 
|
     *          should specify an interface that descends from | 
|
     *          <code>java.util.EventListener</code> | 
|
     * @return an array of all objects registered as | 
|
     *          <code><em>Foo</em>Listener</code>s on this component, | 
|
     *          or an empty array if no such | 
|
     *          listeners have been added | 
|
     * @exception ClassCastException if <code>listenerType</code> | 
|
     *          doesn't specify a class or interface that implements | 
|
     *          <code>java.util.EventListener</code> | 
|
     * | 
|
     * @see #getTreeModelListeners | 
|
     * | 
|
     * @since 1.3 | 
|
*/  | 
|
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {  | 
|
return listenerList.getListeners(listenerType);  | 
|
}  | 
|
    // Serialization support. | 
|
private void writeObject(ObjectOutputStream s) throws IOException {  | 
|
Vector<Object> values = new Vector<Object>();  | 
|
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  |