25
26 package javax.swing.tree;
27
28 import java.util.*;
29 import java.beans.ConstructorProperties;
30 import java.io.*;
31 import javax.swing.event.*;
32
33 /**
34 * A simple tree data model that uses TreeNodes.
35 * For further information and examples that use DefaultTreeModel,
36 * see <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
37 * in <em>The Java Tutorial.</em>
38 * <p>
39 * <strong>Warning:</strong>
40 * Serialized objects of this class will not be compatible with
41 * future Swing releases. The current serialization support is
42 * appropriate for short term storage or RMI between applications running
43 * the same version of Swing. As of 1.4, support for long term storage
44 * of all JavaBeans™
45 * has been added to the <code>java.beans</code> package.
46 * Please see {@link java.beans.XMLEncoder}.
47 *
48 * @author Rob Davis
49 * @author Ray Ryan
50 * @author Scott Violet
51 */
52 @SuppressWarnings("serial") // Same-version serialization only
53 public class DefaultTreeModel implements Serializable, TreeModel {
54 /** Root of the tree. */
55 protected TreeNode root;
56 /** Listeners. */
57 protected EventListenerList listenerList = new EventListenerList();
58 /**
59 * Determines how the <code>isLeaf</code> method figures
60 * out if a node is a leaf node. If true, a node is a leaf
61 * node if it does not allow children. (If it allows
62 * children, it is not a leaf node, even if no children
63 * are present.) That lets you distinguish between <i>folder</i>
64 * nodes and <i>file</i> nodes in a file system, for example.
65 * <p>
66 * If this value is false, then any node which has no
67 * children is a leaf node, and any node may acquire
68 * children.
69 *
70 * @see TreeNode#getAllowsChildren
71 * @see TreeModel#isLeaf
72 * @see #setAsksAllowsChildren
73 */
74 protected boolean asksAllowsChildren;
75
76
77 /**
78 * Creates a tree in which any node can have children.
79 *
109 * @param newValue if true, getAllowsChildren() is messaged, otherwise
110 * isLeaf() is messaged
111 */
112 public void setAsksAllowsChildren(boolean newValue) {
113 asksAllowsChildren = newValue;
114 }
115
116 /**
117 * Tells how leaf nodes are determined.
118 *
119 * @return true if only nodes which do not allow children are
120 * leaf nodes, false if nodes which have no children
121 * (even if allowed) are leaf nodes
122 * @see #asksAllowsChildren
123 */
124 public boolean asksAllowsChildren() {
125 return asksAllowsChildren;
126 }
127
128 /**
129 * Sets the root to <code>root</code>. A null <code>root</code> implies
130 * the tree is to display nothing, and is legal.
131 *
132 * @param root new value of tree root
133 */
134 public void setRoot(TreeNode root) {
135 Object oldRoot = this.root;
136 this.root = root;
137 if (root == null && oldRoot != null) {
138 fireTreeStructureChanged(this, null);
139 }
140 else {
141 nodeStructureChanged(root);
142 }
143 }
144
145 /**
146 * Returns the root of the tree. Returns null only if the tree has
147 * no nodes.
148 *
149 * @return the root of the tree
150 */
151 public Object getRoot() {
152 return root;
153 }
154
155 /**
156 * Returns the index of child in parent.
157 * If either the parent or child is <code>null</code>, returns -1.
158 * @param parent a note in the tree, obtained from this data source
159 * @param child the node we are interested in
160 * @return the index of the child in the parent, or -1
161 * if either the parent or the child is <code>null</code>
162 */
163 public int getIndexOfChild(Object parent, Object child) {
164 if(parent == null || child == null)
165 return -1;
166 return ((TreeNode)parent).getIndex((TreeNode)child);
167 }
168
169 /**
170 * Returns the child of <I>parent</I> at index <I>index</I> in the parent's
171 * child array. <I>parent</I> must be a node previously obtained from
172 * this data source. This should not return null if <i>index</i>
173 * is a valid index for <i>parent</i> (that is <i>index</i> >= 0 &&
174 * <i>index</i> < getChildCount(<i>parent</i>)).
175 *
176 * @param parent a node in the tree, obtained from this data source
177 * @return the child of <I>parent</I> at index <I>index</I>
178 */
179 public Object getChild(Object parent, int index) {
180 return ((TreeNode)parent).getChildAt(index);
181 }
182
183 /**
184 * Returns the number of children of <I>parent</I>. Returns 0 if the node
185 * is a leaf or if it has no children. <I>parent</I> must be a node
186 * previously obtained from this data source.
187 *
188 * @param parent a node in the tree, obtained from this data source
189 * @return the number of children of the node <I>parent</I>
190 */
191 public int getChildCount(Object parent) {
192 return ((TreeNode)parent).getChildCount();
193 }
194
195 /**
196 * Returns whether the specified node is a leaf node.
197 * The way the test is performed depends on the
198 * <code>askAllowsChildren</code> setting.
199 *
200 * @param node the node to check
201 * @return true if the node is a leaf node
202 *
203 * @see #asksAllowsChildren
204 * @see TreeModel#isLeaf
205 */
206 public boolean isLeaf(Object node) {
207 if(asksAllowsChildren)
208 return !((TreeNode)node).getAllowsChildren();
209 return ((TreeNode)node).isLeaf();
210 }
211
212 /**
213 * Invoke this method if you've modified the {@code TreeNode}s upon which
214 * this model depends. The model will notify all of its listeners that the
215 * model has changed.
216 */
217 public void reload() {
218 reload(root);
453 * @param l the listener to add
454 */
455 public void addTreeModelListener(TreeModelListener l) {
456 listenerList.add(TreeModelListener.class, l);
457 }
458
459 /**
460 * Removes a listener previously added with <B>addTreeModelListener()</B>.
461 *
462 * @see #addTreeModelListener
463 * @param l the listener to remove
464 */
465 public void removeTreeModelListener(TreeModelListener l) {
466 listenerList.remove(TreeModelListener.class, l);
467 }
468
469 /**
470 * Returns an array of all the tree model listeners
471 * registered on this model.
472 *
473 * @return all of this model's <code>TreeModelListener</code>s
474 * or an empty
475 * array if no tree model listeners are currently registered
476 *
477 * @see #addTreeModelListener
478 * @see #removeTreeModelListener
479 *
480 * @since 1.4
481 */
482 public TreeModelListener[] getTreeModelListeners() {
483 return listenerList.getListeners(TreeModelListener.class);
484 }
485
486 /**
487 * Notifies all listeners that have registered interest for
488 * notification on this event type. The event instance
489 * is lazily created using the parameters passed into
490 * the fire method.
491 *
492 * @param source the source of the {@code TreeModelEvent};
493 * typically {@code this}
628 // those that are interested in this event
629 for (int i = listeners.length-2; i>=0; i-=2) {
630 if (listeners[i]==TreeModelListener.class) {
631 // Lazily create the event:
632 if (e == null)
633 e = new TreeModelEvent(source, path);
634 ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
635 }
636 }
637 }
638
639 /**
640 * Returns an array of all the objects currently registered
641 * as <code><em>Foo</em>Listener</code>s
642 * upon this model.
643 * <code><em>Foo</em>Listener</code>s are registered using the
644 * <code>add<em>Foo</em>Listener</code> method.
645 *
646 * <p>
647 *
648 * You can specify the <code>listenerType</code> argument
649 * with a class literal,
650 * such as
651 * <code><em>Foo</em>Listener.class</code>.
652 * For example, you can query a
653 * <code>DefaultTreeModel</code> <code>m</code>
654 * for its tree model listeners with the following code:
655 *
656 * <pre>TreeModelListener[] tmls = (TreeModelListener[])(m.getListeners(TreeModelListener.class));</pre>
657 *
658 * If no such listeners exist, this method returns an empty array.
659 *
660 * @param <T> the listener type
661 * @param listenerType the type of listeners requested
662 * @return an array of all objects registered as
663 * <code><em>Foo</em>Listener</code>s on this component,
664 * or an empty array if no such
665 * listeners have been added
666 * @exception ClassCastException if <code>listenerType</code>
667 * doesn't specify a class or interface that implements
668 * <code>java.util.EventListener</code>
669 *
670 * @see #getTreeModelListeners
671 *
672 * @since 1.3
673 */
674 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
675 return listenerList.getListeners(listenerType);
676 }
677
678 // Serialization support.
679 private void writeObject(ObjectOutputStream s) throws IOException {
680 Vector<Object> values = new Vector<Object>();
681
682 s.defaultWriteObject();
683 // Save the root, if its Serializable.
684 if(root != null && root instanceof Serializable) {
685 values.addElement("root");
686 values.addElement(root);
687 }
688 s.writeObject(values);
|
25
26 package javax.swing.tree;
27
28 import java.util.*;
29 import java.beans.ConstructorProperties;
30 import java.io.*;
31 import javax.swing.event.*;
32
33 /**
34 * A simple tree data model that uses TreeNodes.
35 * For further information and examples that use DefaultTreeModel,
36 * see <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
37 * in <em>The Java Tutorial.</em>
38 * <p>
39 * <strong>Warning:</strong>
40 * Serialized objects of this class will not be compatible with
41 * future Swing releases. The current serialization support is
42 * appropriate for short term storage or RMI between applications running
43 * the same version of Swing. As of 1.4, support for long term storage
44 * of all JavaBeans™
45 * has been added to the {@code java.beans} package.
46 * Please see {@link java.beans.XMLEncoder}.
47 *
48 * @author Rob Davis
49 * @author Ray Ryan
50 * @author Scott Violet
51 */
52 @SuppressWarnings("serial") // Same-version serialization only
53 public class DefaultTreeModel implements Serializable, TreeModel {
54 /** Root of the tree. */
55 protected TreeNode root;
56 /** Listeners. */
57 protected EventListenerList listenerList = new EventListenerList();
58 /**
59 * Determines how the {@code isLeaf} method figures
60 * out if a node is a leaf node. If true, a node is a leaf
61 * node if it does not allow children. (If it allows
62 * children, it is not a leaf node, even if no children
63 * are present.) That lets you distinguish between <i>folder</i>
64 * nodes and <i>file</i> nodes in a file system, for example.
65 * <p>
66 * If this value is false, then any node which has no
67 * children is a leaf node, and any node may acquire
68 * children.
69 *
70 * @see TreeNode#getAllowsChildren
71 * @see TreeModel#isLeaf
72 * @see #setAsksAllowsChildren
73 */
74 protected boolean asksAllowsChildren;
75
76
77 /**
78 * Creates a tree in which any node can have children.
79 *
109 * @param newValue if true, getAllowsChildren() is messaged, otherwise
110 * isLeaf() is messaged
111 */
112 public void setAsksAllowsChildren(boolean newValue) {
113 asksAllowsChildren = newValue;
114 }
115
116 /**
117 * Tells how leaf nodes are determined.
118 *
119 * @return true if only nodes which do not allow children are
120 * leaf nodes, false if nodes which have no children
121 * (even if allowed) are leaf nodes
122 * @see #asksAllowsChildren
123 */
124 public boolean asksAllowsChildren() {
125 return asksAllowsChildren;
126 }
127
128 /**
129 * Sets the root to {@code root}. A null {@code root} implies
130 * the tree is to display nothing, and is legal.
131 *
132 * @param root new value of tree root
133 */
134 public void setRoot(TreeNode root) {
135 Object oldRoot = this.root;
136 this.root = root;
137 if (root == null && oldRoot != null) {
138 fireTreeStructureChanged(this, null);
139 }
140 else {
141 nodeStructureChanged(root);
142 }
143 }
144
145 /**
146 * Returns the root of the tree. Returns null only if the tree has
147 * no nodes.
148 *
149 * @return the root of the tree
150 */
151 public Object getRoot() {
152 return root;
153 }
154
155 /**
156 * Returns the index of child in parent.
157 * If either the parent or child is {@code null}, returns -1.
158 * @param parent a note in the tree, obtained from this data source
159 * @param child the node we are interested in
160 * @return the index of the child in the parent, or -1
161 * if either the parent or the child is {@code null}
162 */
163 public int getIndexOfChild(Object parent, Object child) {
164 if(parent == null || child == null)
165 return -1;
166 return ((TreeNode)parent).getIndex((TreeNode)child);
167 }
168
169 /**
170 * Returns the child of <I>parent</I> at index <I>index</I> in the parent's
171 * child array. <I>parent</I> must be a node previously obtained from
172 * this data source. This should not return null if <i>index</i>
173 * is a valid index for <i>parent</i> (that is <i>index</i> >= 0 &&
174 * <i>index</i> < getChildCount(<i>parent</i>)).
175 *
176 * @param parent a node in the tree, obtained from this data source
177 * @return the child of <I>parent</I> at index <I>index</I>
178 */
179 public Object getChild(Object parent, int index) {
180 return ((TreeNode)parent).getChildAt(index);
181 }
182
183 /**
184 * Returns the number of children of <I>parent</I>. Returns 0 if the node
185 * is a leaf or if it has no children. <I>parent</I> must be a node
186 * previously obtained from this data source.
187 *
188 * @param parent a node in the tree, obtained from this data source
189 * @return the number of children of the node <I>parent</I>
190 */
191 public int getChildCount(Object parent) {
192 return ((TreeNode)parent).getChildCount();
193 }
194
195 /**
196 * Returns whether the specified node is a leaf node.
197 * The way the test is performed depends on the
198 * {@code askAllowsChildren} setting.
199 *
200 * @param node the node to check
201 * @return true if the node is a leaf node
202 *
203 * @see #asksAllowsChildren
204 * @see TreeModel#isLeaf
205 */
206 public boolean isLeaf(Object node) {
207 if(asksAllowsChildren)
208 return !((TreeNode)node).getAllowsChildren();
209 return ((TreeNode)node).isLeaf();
210 }
211
212 /**
213 * Invoke this method if you've modified the {@code TreeNode}s upon which
214 * this model depends. The model will notify all of its listeners that the
215 * model has changed.
216 */
217 public void reload() {
218 reload(root);
453 * @param l the listener to add
454 */
455 public void addTreeModelListener(TreeModelListener l) {
456 listenerList.add(TreeModelListener.class, l);
457 }
458
459 /**
460 * Removes a listener previously added with <B>addTreeModelListener()</B>.
461 *
462 * @see #addTreeModelListener
463 * @param l the listener to remove
464 */
465 public void removeTreeModelListener(TreeModelListener l) {
466 listenerList.remove(TreeModelListener.class, l);
467 }
468
469 /**
470 * Returns an array of all the tree model listeners
471 * registered on this model.
472 *
473 * @return all of this model's {@code TreeModelListener}s
474 * or an empty
475 * array if no tree model listeners are currently registered
476 *
477 * @see #addTreeModelListener
478 * @see #removeTreeModelListener
479 *
480 * @since 1.4
481 */
482 public TreeModelListener[] getTreeModelListeners() {
483 return listenerList.getListeners(TreeModelListener.class);
484 }
485
486 /**
487 * Notifies all listeners that have registered interest for
488 * notification on this event type. The event instance
489 * is lazily created using the parameters passed into
490 * the fire method.
491 *
492 * @param source the source of the {@code TreeModelEvent};
493 * typically {@code this}
628 // those that are interested in this event
629 for (int i = listeners.length-2; i>=0; i-=2) {
630 if (listeners[i]==TreeModelListener.class) {
631 // Lazily create the event:
632 if (e == null)
633 e = new TreeModelEvent(source, path);
634 ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
635 }
636 }
637 }
638
639 /**
640 * Returns an array of all the objects currently registered
641 * as <code><em>Foo</em>Listener</code>s
642 * upon this model.
643 * <code><em>Foo</em>Listener</code>s are registered using the
644 * <code>add<em>Foo</em>Listener</code> method.
645 *
646 * <p>
647 *
648 * You can specify the {@code listenerType} argument
649 * with a class literal,
650 * such as
651 * <code><em>Foo</em>Listener.class</code>.
652 * For example, you can query a
653 * {@code DefaultTreeModel m}
654 * for its tree model listeners with the following code:
655 *
656 * <pre>TreeModelListener[] tmls = (TreeModelListener[])(m.getListeners(TreeModelListener.class));</pre>
657 *
658 * If no such listeners exist, this method returns an empty array.
659 *
660 * @param <T> the listener type
661 * @param listenerType the type of listeners requested
662 * @return an array of all objects registered as
663 * <code><em>Foo</em>Listener</code>s on this component,
664 * or an empty array if no such
665 * listeners have been added
666 * @exception ClassCastException if {@code listenerType}
667 * doesn't specify a class or interface that implements
668 * {@code java.util.EventListener}
669 *
670 * @see #getTreeModelListeners
671 *
672 * @since 1.3
673 */
674 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
675 return listenerList.getListeners(listenerType);
676 }
677
678 // Serialization support.
679 private void writeObject(ObjectOutputStream s) throws IOException {
680 Vector<Object> values = new Vector<Object>();
681
682 s.defaultWriteObject();
683 // Save the root, if its Serializable.
684 if(root != null && root instanceof Serializable) {
685 values.addElement("root");
686 values.addElement(root);
687 }
688 s.writeObject(values);
|