1 /* DefaultTreeModel.java --
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package javax
.swing
.tree
;
40 import java
.io
.IOException
;
41 import java
.io
.ObjectInputStream
;
42 import java
.io
.ObjectOutputStream
;
43 import java
.io
.Serializable
;
44 import java
.util
.EventListener
;
46 import javax
.swing
.event
.EventListenerList
;
47 import javax
.swing
.event
.TreeModelEvent
;
48 import javax
.swing
.event
.TreeModelListener
;
49 import javax
.swing
.tree
.DefaultMutableTreeNode
;
54 * @author Andrew Selkirk
56 public class DefaultTreeModel
57 implements Serializable
, TreeModel
59 static final long serialVersionUID
= -2621068368932566998L;
64 protected TreeNode root
= null;
69 protected EventListenerList listenerList
= new EventListenerList();
74 protected boolean asksAllowsChildren
;
77 * Constructor DefaultTreeModel
79 * @param root the tree root.
81 public DefaultTreeModel(TreeNode root
)
84 root
= new DefaultMutableTreeNode();
89 * Constructor DefaultTreeModel
91 * @param root the tree root.
92 * @param asksAllowsChildren TODO
94 public DefaultTreeModel(TreeNode root
, boolean asksAllowsChildren
)
97 this.asksAllowsChildren
= asksAllowsChildren
;
103 * @param obj the object.
104 * @exception IOException TODO
106 private void writeObject(ObjectOutputStream obj
) throws IOException
115 * @exception IOException TODO
116 * @exception ClassNotFoundException TODO
118 private void readObject(ObjectInputStream value0
) throws IOException
,
119 ClassNotFoundException
129 public boolean asksAllowsChildren()
131 return asksAllowsChildren
;
135 * setAsksAllowsChildren
139 public void setAsksAllowsChildren(boolean value
)
141 asksAllowsChildren
= value
;
147 * @param root the root node.
149 public void setRoot(TreeNode root
)
159 public Object
getRoot()
171 public int getIndexOfChild(Object parent
, Object child
)
173 for (int i
= 0; i
< getChildCount(parent
); i
++)
175 if (getChild(parent
, i
).equals(child
))
188 public Object
getChild(Object node
, int idx
)
190 if (node
instanceof TreeNode
)
191 return ((TreeNode
) node
).getChildAt(idx
);
202 public int getChildCount(Object node
)
204 if (node
instanceof TreeNode
)
205 return ((TreeNode
) node
).getChildCount();
216 public boolean isLeaf(Object node
)
218 if (node
instanceof TreeNode
)
219 return ((TreeNode
) node
).isLeaf();
225 * Invoke this method if you've modified the TreeNodes upon
226 * which this model depends. The model will notify all of its
227 * listeners that the model has changed.
235 * Invoke this method if you've modified the TreeNodes upon
236 * which this model depends. The model will notify all of its
237 * listeners that the model has changed.
241 public void reload(TreeNode node
)
247 * Messaged when the user has altered the value for the item
248 * identified by path to newValue. If newValue signifies a truly new
249 * value the model should post a treeNodesChanged event.
250 * This sets the user object of the TreeNode identified by
251 * path and posts a node changed. If you use custom user objects
252 * in the TreeModel you're going to need to subclass this and set
253 * the user object of the changed node to something meaningful.
255 * @param path - path to the node that the user has altered
256 * @param newValue - the new value from the TreeCellEditor
258 public void valueForPathChanged(TreePath path
, Object newValue
)
260 Object node
= path
.getLastPathComponent();
261 if (node
instanceof MutableTreeNode
)
263 ((MutableTreeNode
) node
).setUserObject(newValue
);
266 Object
[] parentPath
= path
.getPath();
267 if (path
.getPathCount() > 1)
269 Object parent
= ((TreeNode
) node
).getParent();
271 ci
[0] = getIndexOfChild(parent
, node
);
273 path
= path
.getParentPath().pathByAddingChild(node
);
276 parentPath
= path
.getParentPath().getPath();
279 fireTreeNodesChanged(this, parentPath
, ci
, c
);
284 * Invoked this to insert newChild at location index in parents children.
285 * This will then message nodesWereInserted to create the appropriate event.
286 * This is the preferred way to add children as it will create the
289 * @param newChild is the node to add to the parent's children
290 * @param parent is the parent of the newChild
291 * @param index is the index of the newChild
293 public void insertNodeInto(MutableTreeNode newChild
, MutableTreeNode parent
,
296 newChild
.setParent(parent
);
297 parent
.insert(newChild
, index
);
298 int[] childIndices
= new int[1];
299 childIndices
[0] = index
;
300 nodesWereInserted(parent
, childIndices
);
304 * Message this to remove node from its parent. This will message
305 * nodesWereRemoved to create the appropriate event. This is the preferred
306 * way to remove a node as it handles the event creation for you.
308 * @param node to be removed
310 public void removeNodeFromParent(MutableTreeNode node
)
312 TreeNode parent
= node
.getParent();
313 Object
[] children
= new Object
[1];
315 int[] childIndices
= new int[1];
316 childIndices
[0] = getIndexOfChild(parent
, node
);
317 node
.removeFromParent();
318 nodesWereRemoved(parent
, childIndices
, children
);
322 * Invoke this method after you've changed how node is to be represented
325 * @param node that was changed
327 public void nodeChanged(TreeNode node
)
329 TreeNode parent
= node
.getParent();
330 int[] childIndices
= new int[1];
331 childIndices
[0] = getIndexOfChild(parent
, node
);
332 Object
[] children
= new Object
[1];
334 fireTreeNodesChanged(this, getPathToRoot(node
), childIndices
, children
);
338 * Invoke this method after you've inserted some TreeNodes
339 * into node. childIndices should be the index of the new elements and must
340 * be sorted in ascending order.
342 * @param parent that had a child added to
343 * @param childIndices of the children added
345 public void nodesWereInserted(TreeNode parent
, int[] childIndices
)
347 Object
[] children
= new Object
[childIndices
.length
];
348 for (int i
= 0; i
< children
.length
; i
++)
349 children
[i
] = getChild(parent
, childIndices
[i
]);
350 fireTreeNodesInserted(this, getPathToRoot(parent
), childIndices
, children
);
354 * Invoke this method after you've removed some TreeNodes from node.
355 * childIndices should be the index of the removed elements and
356 * must be sorted in ascending order. And removedChildren should be the
357 * array of the children objects that were removed.
359 * @param parent that had a child added to
360 * @param childIndices of the children added
361 * @param removedChildren are all the children removed from parent.
363 public void nodesWereRemoved(TreeNode parent
, int[] childIndices
,
364 Object
[] removedChildren
)
366 fireTreeNodesRemoved(this, getPathToRoot(parent
), childIndices
,
371 * Invoke this method after you've changed how the children identified by
372 * childIndices are to be represented in the tree.
374 * @param node that is the parent of the children that changed in a tree.
375 * @param childIndices are the child nodes that changed.
377 public void nodesChanged(TreeNode node
, int[] childIndices
)
379 Object
[] children
= new Object
[childIndices
.length
];
380 for (int i
= 0; i
< children
.length
; i
++)
381 children
[i
] = getChild(node
, childIndices
[i
]);
382 fireTreeNodesChanged(this, getPathToRoot(node
), childIndices
, children
);
386 * Invoke this method if you've totally changed the children of node and
387 * its childrens children. This will post a treeStructureChanged event.
389 * @param node that had its children and grandchildren changed.
391 public void nodeStructureChanged(TreeNode node
)
397 * Builds the parents of node up to and including the root node, where
398 * the original node is the last element in the returned array. The
399 * length of the returned array gives the node's depth in the tree.
401 * @param node - the TreeNode to get the path for
402 * @return TreeNode[] - the path from node to the root
404 public TreeNode
[] getPathToRoot(TreeNode node
)
406 return getPathToRoot(node
, 0);
410 * Builds the parents of node up to and including the root node, where
411 * the original node is the last element in the returned array. The
412 * length of the returned array gives the node's depth in the tree.
414 * @param node - the TreeNode to get the path for
415 * @param depth - an int giving the number of steps already taken
416 * towards the root (on recursive calls), used to size the returned array
417 * @return an array of TreeNodes giving the path from the root to the
420 protected TreeNode
[] getPathToRoot(TreeNode node
, int depth
)
427 return new TreeNode
[depth
];
430 TreeNode
[] path
= getPathToRoot(node
.getParent(), depth
+ 1);
431 path
[path
.length
- depth
- 1] = node
;
436 * Registers a listere to the model.
438 * @param listener the listener to add
440 public void addTreeModelListener(TreeModelListener listener
)
442 listenerList
.add(TreeModelListener
.class, listener
);
446 * Removes a listener from the model.
448 * @param listener the listener to remove
450 public void removeTreeModelListener(TreeModelListener listener
)
452 listenerList
.remove(TreeModelListener
.class, listener
);
456 * Returns all registered <code>TreeModelListener</code> listeners.
458 * @return an array of listeners.
462 public TreeModelListener
[] getTreeModelListeners()
464 return (TreeModelListener
[]) listenerList
465 .getListeners(TreeModelListener
.class);
469 * Notifies all listeners that have registered interest for notification
470 * on this event type. The event instance is lazily created using the parameters
471 * passed into the fire method.
473 * @param source the node being changed
474 * @param path the path to the root node
475 * @param childIndices the indices of the changed elements
476 * @param children the changed elements
478 protected void fireTreeNodesChanged(Object source
, Object
[] path
,
479 int[] childIndices
, Object
[] children
)
481 TreeModelEvent event
= new TreeModelEvent(source
, path
, childIndices
,
484 TreeModelListener
[] listeners
= getTreeModelListeners();
486 for (int i
= listeners
.length
- 1; i
>= 0; --i
)
487 listeners
[i
].treeNodesChanged(event
);
491 * fireTreeNodesInserted
493 * @param source the node where new nodes got inserted
494 * @param path the path to the root node
495 * @param childIndices the indices of the new elements
496 * @param children the new elements
498 protected void fireTreeNodesInserted(Object source
, Object
[] path
,
499 int[] childIndices
, Object
[] children
)
501 TreeModelEvent event
= new TreeModelEvent(source
, path
, childIndices
,
503 TreeModelListener
[] listeners
= getTreeModelListeners();
505 for (int i
= listeners
.length
- 1; i
>= 0; --i
)
506 listeners
[i
].treeNodesInserted(event
);
510 * fireTreeNodesRemoved
512 * @param source the node where nodes got removed-
513 * @param path the path to the root node
514 * @param childIndices the indices of the removed elements
515 * @param children the removed elements
517 protected void fireTreeNodesRemoved(Object source
, Object
[] path
,
518 int[] childIndices
, Object
[] children
)
520 TreeModelEvent event
= new TreeModelEvent(source
, path
, childIndices
,
522 TreeModelListener
[] listeners
= getTreeModelListeners();
524 for (int i
= listeners
.length
- 1; i
>= 0; --i
)
525 listeners
[i
].treeNodesRemoved(event
);
529 * fireTreeStructureChanged
531 * @param source the node where the model has changed
532 * @param path the path to the root node
533 * @param childIndices the indices of the affected elements
534 * @param children the affected elements
536 protected void fireTreeStructureChanged(Object source
, Object
[] path
,
537 int[] childIndices
, Object
[] children
)
539 TreeModelEvent event
= new TreeModelEvent(source
, path
, childIndices
,
541 TreeModelListener
[] listeners
= getTreeModelListeners();
543 for (int i
= listeners
.length
- 1; i
>= 0; --i
)
544 listeners
[i
].treeStructureChanged(event
);
548 * Returns the registered listeners of a given type.
550 * @param listenerType the listener type to return
552 * @return an array of listeners
556 public EventListener
[] getListeners(Class listenerType
)
558 return listenerList
.getListeners(listenerType
);