Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / tree / DefaultTreeModel.java
blobc1ca679d006ba66e73bb364aefd7464f6f2293aa
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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 gnu.classpath.NotImplementedException;
42 import java.io.IOException;
43 import java.io.ObjectInputStream;
44 import java.io.ObjectOutputStream;
45 import java.io.Serializable;
46 import java.util.EventListener;
48 import javax.swing.event.EventListenerList;
49 import javax.swing.event.TreeModelEvent;
50 import javax.swing.event.TreeModelListener;
52 /**
53 * DefaultTreeModel
55 * @author Andrew Selkirk
57 public class DefaultTreeModel
58 implements Serializable, TreeModel
60 static final long serialVersionUID = -2621068368932566998L;
62 /**
63 * root
65 protected TreeNode root = null;
67 /**
68 * listenerList
70 protected EventListenerList listenerList = new EventListenerList();
72 /**
73 * asksAllowsChildren
75 protected boolean asksAllowsChildren;
77 /**
78 * Constructor DefaultTreeModel where any node can have children.
80 * @param root the tree root.
82 public DefaultTreeModel(TreeNode root)
84 this (root, false);
87 /**
88 * Create the DefaultTreeModel that may check if the nodes can have
89 * children or not.
91 * @param aRoot the tree root.
92 * @param asksAllowsChildren if true, each node is asked if it can have
93 * children. If false, the model does not care about this, supposing, that
94 * any node can have children.
96 public DefaultTreeModel(TreeNode aRoot, boolean asksAllowsChildren)
98 if (aRoot == null)
99 aRoot = new DefaultMutableTreeNode();
100 this.root = aRoot;
101 this.asksAllowsChildren = asksAllowsChildren;
105 * writeObject
107 * @param obj the object.
108 * @exception IOException TODO
110 private void writeObject(ObjectOutputStream obj) throws IOException
112 // TODO
116 * readObject
118 * @param value0 TODO
119 * @exception IOException TODO
120 * @exception ClassNotFoundException TODO
122 private void readObject(ObjectInputStream value0) throws IOException,
123 ClassNotFoundException
125 // TODO
129 * asksAllowsChildren
131 * @return boolean
133 public boolean asksAllowsChildren()
135 return asksAllowsChildren;
139 * setAsksAllowsChildren
141 * @param value TODO
143 public void setAsksAllowsChildren(boolean value)
145 asksAllowsChildren = value;
149 * setRoot
151 * @param root the root node.
153 public void setRoot(TreeNode root)
155 this.root = root;
159 * getRoot
161 * @return Object
163 public Object getRoot()
165 return root;
169 * getIndexOfChild
171 * @param parent TODO
172 * @param child TODO
173 * @return int
175 public int getIndexOfChild(Object parent, Object child)
177 for (int i = 0; i < getChildCount(parent); i++)
179 if (getChild(parent, i).equals(child))
180 return i;
182 return -1;
186 * getChild
188 * @param node TODO
189 * @param idx TODO
190 * @return Object
192 public Object getChild(Object node, int idx)
194 if (node instanceof TreeNode)
195 return ((TreeNode) node).getChildAt(idx);
196 else
197 return null;
201 * getChildCount
203 * @param node TODO
204 * @return int
206 public int getChildCount(Object node)
208 if (node instanceof TreeNode)
209 return ((TreeNode) node).getChildCount();
210 else
211 return 0;
215 * isLeaf
217 * @param node TODO
218 * @return boolean
220 public boolean isLeaf(Object node)
222 if (node instanceof TreeNode)
223 return ((TreeNode) node).isLeaf();
224 else
225 return true;
229 * <p>
230 * Invoke this method if you've modified the TreeNodes upon which this model
231 * depends. The model will notify all of its listeners that the model has
232 * changed. It will fire the events, necessary to update the layout caches and
233 * repaint the tree. The tree will <i>not</i> be properly refreshed if you
234 * call the JTree.repaint instead.
235 * </p>
236 * <p>
237 * This method will refresh the information about whole tree from the root. If
238 * only part of the tree should be refreshed, it is more effective to call
239 * {@link #reload(TreeNode)}.
240 * </p>
242 public void reload()
244 // Need to duplicate the code because the root can formally be
245 // no an instance of the TreeNode.
246 int n = getChildCount(root);
247 int[] childIdx = new int[n];
248 Object[] children = new Object[n];
250 for (int i = 0; i < n; i++)
252 childIdx[i] = i;
253 children[i] = getChild(root, i);
256 fireTreeStructureChanged(this, new Object[] { root }, childIdx, children);
260 * Invoke this method if you've modified the TreeNodes upon which this model
261 * depends. The model will notify all of its listeners that the model has
262 * changed. It will fire the events, necessary to update the layout caches and
263 * repaint the tree. The tree will <i>not</i> be properly refreshed if you
264 * call the JTree.repaint instead.
266 * @param node - the tree node, from which the tree nodes have changed
267 * (inclusive). If you do not know this node, call {@link #reload()}
268 * instead.
270 public void reload(TreeNode node)
272 int n = getChildCount(node);
273 int[] childIdx = new int[n];
274 Object[] children = new Object[n];
276 for (int i = 0; i < n; i++)
278 childIdx[i] = i;
279 children[i] = getChild(node, i);
282 fireTreeStructureChanged(this, getPathToRoot(node), childIdx, children);
286 * Messaged when the user has altered the value for the item
287 * identified by path to newValue. If newValue signifies a truly new
288 * value the model should post a treeNodesChanged event.
289 * This sets the user object of the TreeNode identified by
290 * path and posts a node changed. If you use custom user objects
291 * in the TreeModel you're going to need to subclass this and set
292 * the user object of the changed node to something meaningful.
294 * @param path - path to the node that the user has altered
295 * @param newValue - the new value from the TreeCellEditor
297 public void valueForPathChanged(TreePath path, Object newValue)
299 Object node = path.getLastPathComponent();
300 if (node instanceof MutableTreeNode)
302 ((MutableTreeNode) node).setUserObject(newValue);
303 int[] ci = null;
304 Object[] c = null;
305 Object[] parentPath = path.getPath();
306 if (path.getPathCount() > 1)
308 Object parent = ((TreeNode) node).getParent();
309 ci = new int[1];
310 ci[0] = getIndexOfChild(parent, node);
311 node = newValue;
312 path = path.getParentPath().pathByAddingChild(node);
313 c = new Object[1];
314 c[0] = node;
315 parentPath = path.getParentPath().getPath();
318 fireTreeNodesChanged(this, parentPath, ci, c);
323 * Invoked this to insert newChild at location index in parents children.
324 * This will then message nodesWereInserted to create the appropriate event.
325 * This is the preferred way to add children as it will create the
326 * appropriate event.
328 * @param newChild is the node to add to the parent's children
329 * @param parent is the parent of the newChild
330 * @param index is the index of the newChild
332 public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent,
333 int index)
335 newChild.setParent(parent);
336 parent.insert(newChild, index);
337 int[] childIndices = new int[1];
338 childIndices[0] = index;
339 nodesWereInserted(parent, childIndices);
343 * Message this to remove node from its parent. This will message
344 * nodesWereRemoved to create the appropriate event. This is the preferred
345 * way to remove a node as it handles the event creation for you.
347 * @param node to be removed
349 public void removeNodeFromParent(MutableTreeNode node)
351 TreeNode parent = node.getParent();
352 Object[] children = new Object[1];
353 children[0] = node;
354 int[] childIndices = new int[1];
355 childIndices[0] = getIndexOfChild(parent, node);
356 node.removeFromParent();
357 nodesWereRemoved(parent, childIndices, children);
361 * Invoke this method after you've changed how node is to be represented
362 * in the tree.
364 * @param node that was changed
366 public void nodeChanged(TreeNode node)
368 TreeNode parent = node.getParent();
369 int[] childIndices = new int[1];
370 childIndices[0] = getIndexOfChild(parent, node);
371 Object[] children = new Object[1];
372 children[0] = node;
373 fireTreeNodesChanged(this, getPathToRoot(node), childIndices, children);
377 * Invoke this method after you've inserted some TreeNodes
378 * into node. childIndices should be the index of the new elements and must
379 * be sorted in ascending order.
381 * @param parent that had a child added to
382 * @param childIndices of the children added
384 public void nodesWereInserted(TreeNode parent, int[] childIndices)
386 Object[] children = new Object[childIndices.length];
387 for (int i = 0; i < children.length; i++)
388 children[i] = getChild(parent, childIndices[i]);
389 fireTreeNodesInserted(this, getPathToRoot(parent), childIndices, children);
393 * Invoke this method after you've removed some TreeNodes from node.
394 * childIndices should be the index of the removed elements and
395 * must be sorted in ascending order. And removedChildren should be the
396 * array of the children objects that were removed.
398 * @param parent that had a child added to
399 * @param childIndices of the children added
400 * @param removedChildren are all the children removed from parent.
402 public void nodesWereRemoved(TreeNode parent, int[] childIndices,
403 Object[] removedChildren)
405 fireTreeNodesRemoved(this, getPathToRoot(parent), childIndices,
406 removedChildren);
410 * Invoke this method after you've changed how the children identified by
411 * childIndices are to be represented in the tree.
413 * @param node that is the parent of the children that changed in a tree.
414 * @param childIndices are the child nodes that changed.
416 public void nodesChanged(TreeNode node, int[] childIndices)
418 Object[] children = new Object[childIndices.length];
419 for (int i = 0; i < children.length; i++)
420 children[i] = getChild(node, childIndices[i]);
421 fireTreeNodesChanged(this, getPathToRoot(node), childIndices, children);
425 * Invoke this method if you've totally changed the children of node and
426 * its childrens children. This will post a treeStructureChanged event.
428 * @param node that had its children and grandchildren changed.
430 public void nodeStructureChanged(TreeNode node)
432 int n = getChildCount(root);
433 int[] childIdx = new int[n];
434 Object[] children = new Object[n];
436 for (int i = 0; i < n; i++)
438 childIdx[i] = i;
439 children[i] = getChild(root, i);
442 fireTreeStructureChanged(this, new Object[] { root }, childIdx, children);
446 * Builds the parents of node up to and including the root node, where
447 * the original node is the last element in the returned array. The
448 * length of the returned array gives the node's depth in the tree.
450 * @param node - the TreeNode to get the path for
451 * @return TreeNode[] - the path from node to the root
453 public TreeNode[] getPathToRoot(TreeNode node)
455 return getPathToRoot(node, 0);
459 * Builds the parents of node up to and including the root node, where
460 * the original node is the last element in the returned array. The
461 * length of the returned array gives the node's depth in the tree.
463 * @param node - the TreeNode to get the path for
464 * @param depth - an int giving the number of steps already taken
465 * towards the root (on recursive calls), used to size the returned array
466 * @return an array of TreeNodes giving the path from the root to the
467 * specified node
469 protected TreeNode[] getPathToRoot(TreeNode node, int depth)
471 if (node == null)
473 if (depth == 0)
474 return null;
476 return new TreeNode[depth];
479 TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
480 path[path.length - depth - 1] = node;
481 return path;
485 * Registers a listere to the model.
487 * @param listener the listener to add
489 public void addTreeModelListener(TreeModelListener listener)
491 listenerList.add(TreeModelListener.class, listener);
495 * Removes a listener from the model.
497 * @param listener the listener to remove
499 public void removeTreeModelListener(TreeModelListener listener)
501 listenerList.remove(TreeModelListener.class, listener);
505 * Returns all registered <code>TreeModelListener</code> listeners.
507 * @return an array of listeners.
509 * @since 1.4
511 public TreeModelListener[] getTreeModelListeners()
513 return (TreeModelListener[]) listenerList
514 .getListeners(TreeModelListener.class);
518 * Notifies all listeners that have registered interest for notification
519 * on this event type. The event instance is lazily created using the parameters
520 * passed into the fire method.
522 * @param source the node being changed
523 * @param path the path to the root node
524 * @param childIndices the indices of the changed elements
525 * @param children the changed elements
527 protected void fireTreeNodesChanged(Object source, Object[] path,
528 int[] childIndices, Object[] children)
530 TreeModelEvent event = new TreeModelEvent(source, path, childIndices,
531 children);
533 TreeModelListener[] listeners = getTreeModelListeners();
535 for (int i = listeners.length - 1; i >= 0; --i)
536 listeners[i].treeNodesChanged(event);
540 * fireTreeNodesInserted
542 * @param source the node where new nodes got inserted
543 * @param path the path to the root node
544 * @param childIndices the indices of the new elements
545 * @param children the new elements
547 protected void fireTreeNodesInserted(Object source, Object[] path,
548 int[] childIndices, Object[] children)
550 TreeModelEvent event = new TreeModelEvent(source, path, childIndices,
551 children);
552 TreeModelListener[] listeners = getTreeModelListeners();
554 for (int i = listeners.length - 1; i >= 0; --i)
555 listeners[i].treeNodesInserted(event);
559 * fireTreeNodesRemoved
561 * @param source the node where nodes got removed-
562 * @param path the path to the root node
563 * @param childIndices the indices of the removed elements
564 * @param children the removed elements
566 protected void fireTreeNodesRemoved(Object source, Object[] path,
567 int[] childIndices, Object[] children)
569 TreeModelEvent event = new TreeModelEvent(source, path, childIndices,
570 children);
571 TreeModelListener[] listeners = getTreeModelListeners();
573 for (int i = listeners.length - 1; i >= 0; --i)
574 listeners[i].treeNodesRemoved(event);
578 * fireTreeStructureChanged
580 * @param source the node where the model has changed
581 * @param path the path to the root node
582 * @param childIndices the indices of the affected elements
583 * @param children the affected elements
585 protected void fireTreeStructureChanged(Object source, Object[] path,
586 int[] childIndices, Object[] children)
588 TreeModelEvent event = new TreeModelEvent(source, path, childIndices,
589 children);
590 TreeModelListener[] listeners = getTreeModelListeners();
592 for (int i = listeners.length - 1; i >= 0; --i)
593 listeners[i].treeStructureChanged(event);
597 * Returns the registered listeners of a given type.
599 * @param listenerType the listener type to return
601 * @return an array of listeners
603 * @since 1.3
605 public EventListener[] getListeners(Class listenerType)
607 return listenerList.getListeners(listenerType);