Imported GNU Classpath 0.20
[official-gcc.git] / libjava / classpath / javax / swing / JTree.java
blobcfcb2291b2cbb2e1b8e0d4aa3a08abd4e45951a0
1 /* JTree.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;
40 import java.awt.Color;
41 import java.awt.Cursor;
42 import java.awt.Dimension;
43 import java.awt.Font;
44 import java.awt.FontMetrics;
45 import java.awt.Point;
46 import java.awt.Rectangle;
47 import java.awt.event.FocusListener;
48 import java.beans.PropertyChangeListener;
49 import java.io.Serializable;
50 import java.util.Enumeration;
51 import java.util.Hashtable;
52 import java.util.Iterator;
53 import java.util.Locale;
54 import java.util.Vector;
56 import javax.accessibility.Accessible;
57 import javax.accessibility.AccessibleAction;
58 import javax.accessibility.AccessibleComponent;
59 import javax.accessibility.AccessibleContext;
60 import javax.accessibility.AccessibleRole;
61 import javax.accessibility.AccessibleSelection;
62 import javax.accessibility.AccessibleState;
63 import javax.accessibility.AccessibleStateSet;
64 import javax.accessibility.AccessibleText;
65 import javax.accessibility.AccessibleValue;
66 import javax.swing.event.TreeExpansionEvent;
67 import javax.swing.event.TreeExpansionListener;
68 import javax.swing.event.TreeModelEvent;
69 import javax.swing.event.TreeModelListener;
70 import javax.swing.event.TreeSelectionEvent;
71 import javax.swing.event.TreeSelectionListener;
72 import javax.swing.event.TreeWillExpandListener;
73 import javax.swing.plaf.TreeUI;
74 import javax.swing.text.Position;
75 import javax.swing.tree.DefaultMutableTreeNode;
76 import javax.swing.tree.DefaultTreeModel;
77 import javax.swing.tree.DefaultTreeSelectionModel;
78 import javax.swing.tree.ExpandVetoException;
79 import javax.swing.tree.TreeCellEditor;
80 import javax.swing.tree.TreeCellRenderer;
81 import javax.swing.tree.TreeModel;
82 import javax.swing.tree.TreeNode;
83 import javax.swing.tree.TreePath;
84 import javax.swing.tree.TreeSelectionModel;
86 public class JTree extends JComponent implements Scrollable, Accessible
89 /**
90 * This class implements accessibility support for the JTree class. It
91 * provides an implementation of the Java Accessibility API appropriate
92 * to tree user-interface elements.
94 protected class AccessibleJTree extends JComponent.AccessibleJComponent
95 implements AccessibleSelection, TreeSelectionListener, TreeModelListener,
96 TreeExpansionListener
99 /**
100 * This class implements accessibility support for the JTree child. It provides
101 * an implementation of the Java Accessibility API appropriate to tree nodes.
103 protected class AccessibleJTreeNode extends AccessibleContext
104 implements Accessible, AccessibleComponent, AccessibleSelection,
105 AccessibleAction
108 private JTree tree;
109 private TreePath tp;
110 private Accessible acc;
111 private AccessibleStateSet states;
112 private Vector selectionList;
113 private Vector actionList;
114 private TreeModel mod;
115 private Cursor cursor;
118 * Constructs an AccessibleJTreeNode
120 * @param t - the current tree
121 * @param p - the current path to be dealt with
122 * @param ap - the accessible object to use
124 public AccessibleJTreeNode(JTree t, TreePath p, Accessible ap)
126 states = new AccessibleStateSet();
127 selectionList = new Vector();
128 actionList = new Vector();
129 mod = tree.getModel();
130 cursor = JTree.this.getCursor();
132 tree = t;
133 tp = p;
134 acc = ap;
136 // Add all the children of this path that may already be
137 // selected to the selection list.
138 TreePath[] selected = tree.getSelectionPaths();
139 for (int i = 0; i < selected.length; i++)
141 TreePath sel = selected[i];
142 if ((sel.getParentPath()).equals(tp))
143 selectionList.add(sel);
146 // Add all the actions available for a node to
147 // the action list.
148 actionList.add("EXPAND");
149 actionList.add("COLLAPSE");
150 actionList.add("EDIT");
151 actionList.add("SELECT");
152 actionList.add("DESELECT");
156 * Adds the specified selected item in the object to the object's
157 * selection.
159 * @param i - the i-th child of this node.
161 public void addAccessibleSelection(int i)
163 if (mod != null)
165 Object child = mod.getChild(tp.getLastPathComponent(), i);
166 if (child != null)
168 if (!states.contains(AccessibleState.MULTISELECTABLE))
169 clearAccessibleSelection();
170 selectionList.add(child);
171 tree.addSelectionPath(tp.pathByAddingChild(child));
177 * Adds the specified focus listener to receive focus events
178 * from this component.
180 * @param l - the new focus listener
182 public void addFocusListener(FocusListener l)
184 tree.addFocusListener(l);
188 * Add a PropertyChangeListener to the listener list.
190 * @param l - the new property change listener
192 public void addPropertyChangeListener(PropertyChangeListener l)
194 // Nothing to do here.
198 * Clears the selection in the object, so that nothing in the
199 * object is selected.
201 public void clearAccessibleSelection()
203 selectionList.clear();
207 * Checks whether the specified point is within this object's
208 * bounds, where the point's x and y coordinates are defined to be
209 * relative to the coordinate system of the object.
211 * @param p - the point to check
212 * @return true if p is in the bounds
214 public boolean contains(Point p)
216 return getBounds().contains(p);
220 * Perform the specified Action on the tree node.
222 * @param i - the i-th action to perform
223 * @return true if the the action was performed; else false.
225 public boolean doAccessibleAction(int i)
227 if (i >= actionList.size() || i < 0)
228 return false;
230 if (actionList.get(i).equals("EXPAND"))
231 tree.expandPath(tp);
232 else if (actionList.get(i).equals("COLLAPSE"))
233 tree.collapsePath(tp);
234 else if (actionList.get(i).equals("SELECT"))
235 tree.addSelectionPath(tp);
236 else if (actionList.get(i).equals("DESELECT"))
237 tree.removeSelectionPath(tp);
238 else if (actionList.get(i).equals("EDIT"))
239 tree.startEditingAtPath(tp);
240 else
241 return false;
242 return true;
246 * Get the AccessibleAction associated with this object.
248 * @return the action
250 public AccessibleAction getAccessibleAction()
252 return this;
256 * Returns the number of accessible actions available in this tree node.
258 * @return the number of actions
260 public int getAccessibleActionCount()
262 return actionList.size();
266 * Return a description of the specified action of the tree node.
268 * @param i - the i-th action's description
269 * @return a description of the action
271 public String getAccessibleActionDescription(int i)
273 if (i < 0 || i >= actionList.size())
274 return (actionList.get(i)).toString();
275 return super.getAccessibleDescription();
279 * Returns the Accessible child, if one exists, contained at the
280 * local coordinate Point.
282 * @param p - the point of the accessible
283 * @return the accessible at point p if it exists
285 public Accessible getAccessibleAt(Point p)
287 TreePath acc = tree.getClosestPathForLocation(p.x, p.y);
288 if (acc != null)
289 return new AccessibleJTreeNode(tree, acc, this);
290 return null;
294 * Return the specified Accessible child of the object.
296 * @param i - the i-th child of the current path
297 * @return the child if it exists
299 public Accessible getAccessibleChild(int i)
301 if (mod != null)
303 Object child = mod.getChild(tp.getLastPathComponent(), i);
304 if (child != null)
305 return new AccessibleJTreeNode(tree, tp.pathByAddingChild(child),
306 acc);
308 return null;
312 * Returns the number of accessible children in the object.
314 * @return the number of children the current node has
316 public int getAccessibleChildrenCount()
318 TreeModel mod = getModel();
319 if (mod != null)
320 return mod.getChildCount(tp.getLastPathComponent());
321 return 0;
325 * Get the AccessibleComponent associated with this object.
327 * @return the accessible component if it is supported.
329 public AccessibleComponent getAccessibleComponent()
331 return this;
335 * Get the AccessibleContext associated with this tree node.
337 * @return an instance of this class
339 public AccessibleContext getAccessibleContext()
341 return this;
345 * Get the accessible description of this object.
347 * @return the accessible description
349 public String getAccessibleDescription()
351 return super.getAccessibleDescription();
355 * Get the index of this object in its accessible parent.
357 * @return the index of this in the parent.
359 public int getAccessibleIndexInParent()
361 AccessibleContext parent = getAccessibleParent().getAccessibleContext();
362 if (parent != null)
363 for (int i = 0; i < parent.getAccessibleChildrenCount(); i++)
365 if ((parent.getAccessibleChild(i)).equals(this))
366 return i;
368 return -1;
372 * Get the accessible name of this object.
374 * @return the accessible name
376 public String getAccessibleName()
378 return super.getAccessibleName();
382 * Get the Accessible parent of this object.
384 * @return the accessible parent if it exists.
386 public Accessible getAccessibleParent()
388 return super.getAccessibleParent();
392 * Get the role of this object.
394 * @return the accessible role
396 public AccessibleRole getAccessibleRole()
398 return AccessibleJTree.this.getAccessibleRole();
402 * Get the AccessibleSelection associated with this object if one exists.
404 * @return the accessible selection for this.
406 public AccessibleSelection getAccessibleSelection()
408 return this;
412 * Returns an Accessible representing the specified selected item
413 * in the object.
415 * @return the accessible representing a certain selected item.
417 public Accessible getAccessibleSelection(int i)
419 if (i > 0 && i < getAccessibleSelectionCount())
420 return new AccessibleJTreeNode(tree,
421 tp.pathByAddingChild(selectionList.get(i)), acc);
422 return null;
426 * Returns the number of items currently selected.
428 * @return the number of items selected.
430 public int getAccessibleSelectionCount()
432 return selectionList.size();
436 * Get the state set of this object.
438 * @return the state set for this object
440 public AccessibleStateSet getAccessibleStateSet()
442 if (isVisible())
443 states.add(AccessibleState.VISIBLE);
444 if (tree.isCollapsed(tp))
445 states.add(AccessibleState.COLLAPSED);
446 if (tree.isEditable())
447 states.add(AccessibleState.EDITABLE);
448 if (mod != null &&
449 !mod.isLeaf(tp.getLastPathComponent()))
450 states.add(AccessibleState.EXPANDABLE);
451 if (tree.isExpanded(tp))
452 states.add(AccessibleState.EXPANDED);
453 if (isFocusable())
454 states.add(AccessibleState.FOCUSABLE);
455 if (hasFocus())
456 states.add(AccessibleState.FOCUSED);
457 if (tree.getSelectionModel().getSelectionMode() !=
458 TreeSelectionModel.SINGLE_TREE_SELECTION)
459 states.add(AccessibleState.MULTISELECTABLE);
460 if (tree.isOpaque())
461 states.add(AccessibleState.OPAQUE);
462 if (tree.isPathSelected(tp))
463 states.add(AccessibleState.SELECTED);
464 if (isShowing())
465 states.add(AccessibleState.SHOWING);
467 states.add(AccessibleState.SELECTABLE);
468 return states;
472 * Get the AccessibleText associated with this object if one exists.
474 * @return the accessible text
476 public AccessibleText getAccessibleText()
478 return super.getAccessibleText();
482 * Get the AccessibleValue associated with this object if one exists.
484 * @return the accessible value if it exists
486 public AccessibleValue getAccessibleValue()
488 return super.getAccessibleValue();
492 * Get the background color of this object.
494 * @return the color of the background.
496 public Color getBackground()
498 return tree.getBackground();
502 * Gets the bounds of this object in the form of a Rectangle object.
504 * @return the bounds of the current node.
506 public Rectangle getBounds()
508 return tree.getPathBounds(tp);
512 * Gets the Cursor of this object.
514 * @return the cursor for the current node
516 public Cursor getCursor()
518 return cursor;
522 * Gets the Font of this object.
524 * @return the font for the current node
526 public Font getFont()
528 return tree.getFont();
532 * Gets the FontMetrics of this object.
534 * @param f - the current font.
535 * @return the font metrics for the given font.
537 public FontMetrics getFontMetrics(Font f)
539 return tree.getFontMetrics(f);
543 * Get the foreground color of this object.
545 * @return the foreground for this object.
547 public Color getForeground()
549 return tree.getForeground();
553 * Gets the locale of the component.
555 * @return the locale of the component.
557 public Locale getLocale()
559 return tree.getLocale();
563 * Gets the location of the object relative to the
564 * parent in the form of a point specifying the object's
565 * top-left corner in the screen's coordinate space.
567 * @return the location of the current node.
569 public Point getLocation()
571 return getLocationInJTree();
575 * Returns the location in the tree.
577 * @return the location in the JTree.
579 protected Point getLocationInJTree()
581 Rectangle bounds = tree.getPathBounds(tp);
582 return new Point(bounds.x, bounds.y);
586 * Returns the location of the object on the screen.
588 * @return the location of the object on the screen.
590 public Point getLocationOnScreen()
592 Point loc = getLocation();
593 SwingUtilities.convertPointToScreen(loc, tree);
594 return loc;
598 * Returns the size of this object in the form of a Dimension object.
600 * @return the size of the object
602 public Dimension getSize()
604 Rectangle b = getBounds();
605 return b.getSize();
609 * Returns true if the current child of this object is selected.
611 * @param i - the child of the current node
612 * @return true if the child is selected.
614 public boolean isAccessibleChildSelected(int i)
616 Object child = mod.getChild(tp.getLastPathComponent(), i);
617 if (child != null)
618 return tree.isPathSelected(tp.pathByAddingChild(child));
619 return false;
623 * Determines if the object is enabled.
625 * @return true if the tree is enabled
627 public boolean isEnabled()
629 return tree.isEnabled();
633 * Returns whether this object can accept focus or not.
635 * @return true, it is always focus traversable
637 public boolean isFocusTraversable()
639 return true;
643 * Determines if the object is showing.
645 * @return true if the object is visible and the
646 * parent is visible.
648 public boolean isShowing()
650 return isVisible() && tree.isShowing();
654 * Determines if the object is visible.
656 * @return true if the object is visible.
658 public boolean isVisible()
660 return tree.isVisible(tp);
664 * Removes the specified selected item in the object from the
665 * object's selection.
667 * @param i - the specified item to remove
669 public void removeAccessibleSelection(int i)
671 if (mod != null)
673 Object child = mod.getChild(tp.getLastPathComponent(), i);
674 if (child != null)
676 if (!states.contains(AccessibleState.MULTISELECTABLE))
677 clearAccessibleSelection();
678 if (selectionList.contains(child))
680 selectionList.remove(child);
681 tree.removeSelectionPath(tp.pathByAddingChild(child));
688 * Removes the specified focus listener so it no longer receives focus
689 * events from this component.
691 * @param l - the focus listener to remove
693 public void removeFocusListener(FocusListener l)
695 tree.removeFocusListener(l);
699 * Remove a PropertyChangeListener from the listener list.
701 * @param l - the property change listener to remove.
703 public void removePropertyChangeListener(PropertyChangeListener l)
705 // Nothing to do here.
709 * Requests focus for this object.
711 public void requestFocus()
713 tree.requestFocus();
717 * Causes every selected item in the object to be selected if the object
718 * supports multiple selections.
720 public void selectAllAccessibleSelection()
722 Object parent = tp.getLastPathComponent();
723 if (mod != null)
725 for (int i = 0; i < mod.getChildCount(parent); i++)
727 Object child = mod.getChild(parent, i);
728 if (child != null)
730 if (!states.contains(AccessibleState.MULTISELECTABLE))
731 clearAccessibleSelection();
732 if (selectionList.contains(child))
734 selectionList.add(child);
735 tree.addSelectionPath(tp.pathByAddingChild(child));
743 * Set the accessible description of this object.
745 * @param s - the string to set the accessible description to.
747 public void setAccessibleDescription(String s)
749 super.setAccessibleDescription(s);
753 * Set the localized accessible name of this object.
755 * @param s - the string to set the accessible name to.
757 public void setAccessibleName(String s)
759 super.setAccessibleName(s);
763 * Set the background color of this object.
765 * @param c - the color to set the background to.
767 public void setBackground(Color c)
769 // Nothing to do here.
773 * Sets the bounds of this object in the form of a Rectangle object.
775 * @param r - the bounds to set the object o
777 public void setBounds(Rectangle r)
779 // Nothing to do here.
783 * Sets the Cursor of this object.
785 * @param c - the new cursor
787 public void setCursor(Cursor c)
789 cursor = c;
793 * Sets the enabled state of the object.
795 * @param b - boolean to enable or disable object
797 public void setEnabled(boolean b)
799 // Nothing to do here.
803 * Sets the Font of this object.
805 * @param f - the new font.
807 public void setFont(Font f)
809 // Nothing to do here.
813 * Sets the foreground color of this object.
815 * @param c - the new foreground color.
817 public void setForeground(Color c)
819 // Nothing to do here.
823 * Sets the location of the object relative to the parent.
825 * @param p - the new location for the object.
827 public void setLocation(Point p)
829 // Nothing to do here.
833 * Resizes this object so that it has width and height.
835 * @param d - the new size for the object.
837 public void setSize(Dimension d)
839 // Nothing to do here.
843 * Sets the visible state of the object.
845 * @param b - sets the objects visibility.
847 public void setVisible(boolean b)
849 // Nothing to do here.
854 * Constructor
856 public AccessibleJTree()
858 // Nothing to do here.
862 * Adds the specified selected item in the object to the object's selection.
864 * @param i - the row to add to the tree's selection
866 public void addAccessibleSelection(int i)
868 addSelectionInterval(i, i);
872 * Clears the selection in the object, so that nothing in the object is selected.
874 public void clearAccessibleSelection()
876 clearSelection();
880 * Fire a visible data property change notification.
882 public void fireVisibleDataPropertyChange()
884 treeDidChange();
888 * Returns the Accessible child, if one exists, contained at the local
889 * coordinate Point.
891 * @param p - the point of the accessible to get.
892 * @return the accessible at point p.
894 public Accessible getAccessibleAt(Point p)
896 TreePath tp = getClosestPathForLocation(p.x, p.y);
897 if (tp != null)
898 return new AccessibleJTreeNode(JTree.this, tp, null);
899 return null;
903 * Return the nth Accessible child of the object.
905 * @param i - the accessible child to get
906 * @return the i-th child
908 public Accessible getAccessibleChild(int i)
910 return null;
914 * Returns the number of top-level children nodes of this JTree.
916 * @return the number of top-level children
918 public int getAccessibleChildrenCount()
920 TreeModel model = getModel();
921 if (model != null)
922 return model.getChildCount(model.getRoot());
923 return 0;
927 * Get the index of this object in its accessible parent.
929 * @return the index of this object.
931 public int getAccessibleIndexInParent()
933 return 0;
937 * Get the role of this object.
939 * @return the role of this object
941 public AccessibleRole getAccessibleRole()
943 return AccessibleRole.TREE;
947 * Get the AccessibleSelection associated with this object.
949 * @return the accessible selection of the tree
951 public AccessibleSelection getAccessibleSelection()
953 TreeModel mod = getModel();
954 if (mod != null)
955 return (new AccessibleJTreeNode(JTree.this,
956 new TreePath(mod.getRoot()), null)).getAccessibleSelection();
957 return null;
961 * Returns an Accessible representing the specified selected item in the object.
963 * @return the i-th accessible in the selection
965 public Accessible getAccessibleSelection(int i)
967 TreeModel mod = getModel();
968 if (mod != null)
969 return (new AccessibleJTreeNode(JTree.this,
970 new TreePath(mod.getRoot()), null)).getAccessibleSelection(i);
971 return null;
975 * Returns the number of items currently selected.
977 * @return the number of selected accessibles.
979 public int getAccessibleSelectionCount()
981 return getSelectionCount();
985 * Returns true if the current child of this object is selected.
987 * @param i - the child of this object
988 * @return true if the i-th child is selected.
990 public boolean isAccessibleChildSelected(int i)
992 // Nothing to do here.
993 return false;
997 * Removes the specified selected item in the object from the object's
998 * selection.
1000 * @param i - the i-th selected item to remove
1002 public void removeAccessibleSelection(int i)
1004 removeSelectionInterval(i, i);
1008 * Causes every selected item in the object to be selected if the object
1009 * supports multiple selections.
1011 public void selectAllAccessibleSelection()
1013 if (getSelectionModel().getSelectionMode() !=
1014 TreeSelectionModel.SINGLE_TREE_SELECTION)
1015 addSelectionInterval(0, getVisibleRowCount());
1019 * Tree Collapsed notification
1021 * @param e - the event
1023 public void treeCollapsed(TreeExpansionEvent e)
1025 fireTreeCollapsed(e.getPath());
1029 * Tree Model Expansion notification.
1031 * @param e - the event
1033 public void treeExpanded(TreeExpansionEvent e)
1035 fireTreeExpanded(e.getPath());
1039 * Tree Model Node change notification.
1041 * @param e - the event
1043 public void treeNodesChanged(TreeModelEvent e)
1045 // Nothing to do here.
1049 * Tree Model Node change notification.
1051 * @param e - the event
1053 public void treeNodesInserted(TreeModelEvent e)
1055 // Nothing to do here.
1059 * Tree Model Node change notification.
1061 * @param e - the event
1063 public void treeNodesRemoved(TreeModelEvent e)
1065 // Nothing to do here.
1069 * Tree Model structure change change notification.
1071 * @param e - the event
1073 public void treeStructureChanged(TreeModelEvent e)
1075 // Nothing to do here.
1079 * Tree Selection Listener value change method.
1081 * @param e - the event
1083 public void valueChanged(TreeSelectionEvent e)
1085 fireValueChanged(e);
1089 public static class DynamicUtilTreeNode extends DefaultMutableTreeNode
1091 protected Object childValue;
1093 protected boolean loadedChildren;
1096 * Currently not set or used by this class. It might be set and used in
1097 * later versions of this class.
1099 protected boolean hasChildren;
1101 public DynamicUtilTreeNode(Object value, Object children)
1103 super(value);
1104 childValue = children;
1105 loadedChildren = false;
1108 public int getChildCount()
1110 loadChildren();
1111 return super.getChildCount();
1114 protected void loadChildren()
1116 if (!loadedChildren)
1118 createChildren(this, childValue);
1119 loadedChildren = true;
1123 public Enumeration children()
1125 loadChildren();
1126 return super.children();
1130 * Returns the child node at position <code>pos</code>. Subclassed
1131 * here to load the children if necessary.
1133 * @param pos the position of the child node to fetch
1135 * @return the childnode at the specified position
1137 public TreeNode getChildAt(int pos)
1139 loadChildren();
1140 return super.getChildAt(pos);
1143 public boolean isLeaf()
1145 return (childValue == null || !(childValue instanceof Hashtable
1146 || childValue instanceof Vector || childValue.getClass()
1147 .isArray()));
1150 public static void createChildren(DefaultMutableTreeNode parent,
1151 Object children)
1153 if (children instanceof Hashtable)
1155 Hashtable tab = (Hashtable) children;
1156 Enumeration e = tab.keys();
1157 while (e.hasMoreElements())
1159 Object key = e.nextElement();
1160 Object val = tab.get(key);
1161 parent.add(new DynamicUtilTreeNode(key, val));
1164 else if (children instanceof Vector)
1166 Iterator i = ((Vector) children).iterator();
1167 while (i.hasNext())
1169 Object n = i.next();
1170 parent.add(new DynamicUtilTreeNode(n, n));
1173 else if (children != null && children.getClass().isArray())
1175 Object[] arr = (Object[]) children;
1176 for (int i = 0; i < arr.length; ++i)
1177 parent.add(new DynamicUtilTreeNode(arr[i], arr[i]));
1183 * Listens to the model of the JTree and updates the property
1184 * <code>expandedState</code> if nodes are removed or changed.
1186 protected class TreeModelHandler implements TreeModelListener
1190 * Creates a new instance of TreeModelHandler.
1192 protected TreeModelHandler()
1194 // Nothing to do here.
1198 * Notifies when a node has changed in some ways. This does not include
1199 * that a node has changed its location or changed it's children. It
1200 * only means that some attributes of the node have changed that might
1201 * affect its presentation.
1203 * This method is called after the actual change occured.
1205 * @param ev the TreeModelEvent describing the change
1207 public void treeNodesChanged(TreeModelEvent ev)
1209 // Nothing to do here.
1213 * Notifies when a node is inserted into the tree.
1215 * This method is called after the actual change occured.
1217 * @param ev the TreeModelEvent describing the change
1219 public void treeNodesInserted(TreeModelEvent ev)
1221 // nothing to do here
1225 * Notifies when a node is removed from the tree.
1227 * This method is called after the actual change occured.
1229 * @param ev the TreeModelEvent describing the change
1231 public void treeNodesRemoved(TreeModelEvent ev)
1233 // TODO: The API docs suggest that this method should do something
1234 // but I cannot really see what has to be done here ...
1238 * Notifies when the structure of the tree is changed.
1240 * This method is called after the actual change occured.
1242 * @param ev the TreeModelEvent describing the change
1244 public void treeStructureChanged(TreeModelEvent ev)
1246 // Set state of new path.
1247 TreePath path = ev.getTreePath();
1248 setExpandedState(path, isExpanded(path));
1253 * This redirects TreeSelectionEvents and rewrites the source of it to be
1254 * this JTree. This is typically done when the tree model generates an
1255 * event, but the JTree object associated with that model should be listed
1256 * as the actual source of the event.
1258 protected class TreeSelectionRedirector implements TreeSelectionListener,
1259 Serializable
1261 /** The serial version UID. */
1262 private static final long serialVersionUID = -3505069663646241664L;
1265 * Creates a new instance of TreeSelectionRedirector
1267 protected TreeSelectionRedirector()
1269 // Nothing to do here.
1273 * Notifies when the tree selection changes.
1275 * @param ev the TreeSelectionEvent that describes the change
1277 public void valueChanged(TreeSelectionEvent ev)
1279 TreeSelectionEvent rewritten =
1280 (TreeSelectionEvent) ev.cloneWithSource(JTree.this);
1281 fireValueChanged(rewritten);
1282 JTree.this.repaint();
1287 * A TreeModel that does not allow anything to be selected.
1289 protected static class EmptySelectionModel extends DefaultTreeSelectionModel
1291 /** The serial version UID. */
1292 private static final long serialVersionUID = -5815023306225701477L;
1295 * The shared instance of this model.
1297 protected static final EmptySelectionModel sharedInstance =
1298 new EmptySelectionModel();
1301 * Creates a new instance of EmptySelectionModel.
1303 protected EmptySelectionModel()
1305 // Nothing to do here.
1309 * Returns the shared instance of EmptySelectionModel.
1311 * @return the shared instance of EmptySelectionModel
1313 public static EmptySelectionModel sharedInstance()
1315 return sharedInstance;
1319 * This catches attempts to set a selection and sets nothing instead.
1321 * @param paths not used here
1323 public void setSelectionPaths(TreePath[] paths)
1325 // We don't allow selections in this class.
1329 * This catches attempts to add something to the selection.
1331 * @param paths not used here
1333 public void addSelectionPaths(TreePath[] paths)
1335 // We don't allow selections in this class.
1339 * This catches attempts to remove something from the selection.
1341 * @param paths not used here
1343 public void removeSelectionPaths(TreePath[] paths)
1345 // We don't allow selections in this class.
1349 private static final long serialVersionUID = 7559816092864483649L;
1351 public static final String CELL_EDITOR_PROPERTY = "cellEditor";
1353 public static final String CELL_RENDERER_PROPERTY = "cellRenderer";
1355 public static final String EDITABLE_PROPERTY = "editable";
1357 public static final String INVOKES_STOP_CELL_EDITING_PROPERTY =
1358 "invokesStopCellEditing";
1360 public static final String LARGE_MODEL_PROPERTY = "largeModel";
1362 public static final String ROOT_VISIBLE_PROPERTY = "rootVisible";
1364 public static final String ROW_HEIGHT_PROPERTY = "rowHeight";
1366 public static final String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand";
1368 public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
1370 public static final String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
1372 public static final String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount";
1374 public static final String TREE_MODEL_PROPERTY = "model";
1376 public static final String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
1378 /** @since 1.3 */
1379 public static final String ANCHOR_SELECTION_PATH_PROPERTY =
1380 "anchorSelectionPath";
1382 /** @since 1.3 */
1383 public static final String LEAD_SELECTION_PATH_PROPERTY = "leadSelectionPath";
1385 /** @since 1.3 */
1386 public static final String EXPANDS_SELECTED_PATHS_PROPERTY =
1387 "expandsSelectedPaths";
1389 private static final Object EXPANDED = new Object();
1391 private static final Object COLLAPSED = new Object();
1393 private boolean dragEnabled;
1395 private boolean expandsSelectedPaths;
1397 private TreePath anchorSelectionPath;
1399 private TreePath leadSelectionPath;
1402 * This contains the state of all nodes in the tree. Al/ entries map the
1403 * TreePath of a note to to its state. Valid states are EXPANDED and
1404 * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED.
1406 private Hashtable nodeStates = new Hashtable();
1408 protected transient TreeCellEditor cellEditor;
1410 protected transient TreeCellRenderer cellRenderer;
1412 protected boolean editable;
1414 protected boolean invokesStopCellEditing;
1416 protected boolean largeModel;
1418 protected boolean rootVisible;
1420 protected int rowHeight;
1422 protected boolean scrollsOnExpand;
1424 protected transient TreeSelectionModel selectionModel;
1426 protected boolean showsRootHandles;
1428 protected int toggleClickCount;
1430 protected transient TreeModel treeModel;
1432 protected int visibleRowCount;
1435 * Handles TreeModelEvents to update the expandedState.
1437 protected transient TreeModelListener treeModelListener;
1440 * Redirects TreeSelectionEvents so that the source is this JTree.
1442 protected TreeSelectionRedirector selectionRedirector =
1443 new TreeSelectionRedirector();
1446 * Creates a new <code>JTree</code> object.
1448 public JTree()
1450 this(createTreeModel(null));
1454 * Creates a new <code>JTree</code> object.
1456 * @param value the initial nodes in the tree
1458 public JTree(Hashtable value)
1460 this(createTreeModel(value));
1464 * Creates a new <code>JTree</code> object.
1466 * @param value the initial nodes in the tree
1468 public JTree(Object[] value)
1470 this(createTreeModel(value));
1474 * Creates a new <code>JTree</code> object.
1476 * @param model the model to use
1478 public JTree(TreeModel model)
1480 updateUI();
1481 setRootVisible(true);
1482 setModel(model);
1483 setSelectionModel(new EmptySelectionModel());
1484 selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
1488 * Creates a new <code>JTree</code> object.
1490 * @param root the root node
1492 public JTree(TreeNode root)
1494 this(root, false);
1498 * Creates a new <code>JTree</code> object.
1500 * @param root the root node
1501 * @param asksAllowChildren if false, all nodes without children are leaf
1502 * nodes. If true, only nodes that do not allow children are leaf
1503 * nodes.
1505 public JTree(TreeNode root, boolean asksAllowChildren)
1507 this(new DefaultTreeModel(root, asksAllowChildren));
1511 * Creates a new <code>JTree</code> object.
1513 * @param value the initial nodes in the tree
1515 public JTree(Vector value)
1517 this(createTreeModel(value));
1520 public int getRowForPath(TreePath path)
1522 TreeUI ui = getUI();
1524 if (ui != null)
1525 return ui.getRowForPath(this, path);
1527 return -1;
1530 public TreePath getPathForRow(int row)
1532 TreeUI ui = getUI();
1533 return ui != null ? ui.getPathForRow(this, row) : null;
1536 protected TreePath[] getPathBetweenRows(int index0, int index1)
1538 TreeUI ui = getUI();
1540 if (ui == null)
1541 return null;
1543 int minIndex = Math.min(index0, index1);
1544 int maxIndex = Math.max(index0, index1);
1545 TreePath[] paths = new TreePath[maxIndex - minIndex + 1];
1547 for (int i = minIndex; i <= maxIndex; ++i)
1548 paths[i - minIndex] = ui.getPathForRow(this, i);
1550 return paths;
1554 * Creates a new <code>TreeModel</code> object.
1556 * @param value the values stored in the model
1558 protected static TreeModel createTreeModel(Object value)
1560 return new DefaultTreeModel(new DynamicUtilTreeNode(value, value));
1564 * Return the UI associated with this <code>JTree</code> object.
1566 * @return the associated <code>TreeUI</code> object
1568 public TreeUI getUI()
1570 return (TreeUI) ui;
1574 * Sets the UI associated with this <code>JTree</code> object.
1576 * @param ui the <code>TreeUI</code> to associate
1578 public void setUI(TreeUI ui)
1580 super.setUI(ui);
1584 * This method resets the UI used to the Look and Feel defaults..
1586 public void updateUI()
1588 setUI((TreeUI) UIManager.getUI(this));
1592 * This method returns the String ID of the UI class of Separator.
1594 * @return The UI class' String ID.
1596 public String getUIClassID()
1598 return "TreeUI";
1602 * Gets the AccessibleContext associated with this
1603 * <code>JTree</code>.
1605 * @return the associated context
1607 public AccessibleContext getAccessibleContext()
1609 return new AccessibleJTree();
1613 * Returns the preferred viewport size.
1615 * @return the preferred size
1617 public Dimension getPreferredScrollableViewportSize()
1619 return new Dimension (getPreferredSize().width, getVisibleRowCount()*getRowHeight());
1622 public int getScrollableUnitIncrement(Rectangle visibleRect,
1623 int orientation, int direction)
1625 return 1;
1628 public int getScrollableBlockIncrement(Rectangle visibleRect,
1629 int orientation, int direction)
1631 return 1;
1634 public boolean getScrollableTracksViewportHeight()
1636 if (getParent() instanceof JViewport)
1637 return ((JViewport) getParent()).getHeight() > getPreferredSize().height;
1638 return false;
1641 public boolean getScrollableTracksViewportWidth()
1643 if (getParent() instanceof JViewport)
1644 return ((JViewport) getParent()).getWidth() > getPreferredSize().width;
1645 return false;
1649 * Adds a <code>TreeExpansionListener</code> object to the tree.
1651 * @param listener the listener to add
1653 public void addTreeExpansionListener(TreeExpansionListener listener)
1655 listenerList.add(TreeExpansionListener.class, listener);
1659 * Removes a <code>TreeExpansionListener</code> object from the tree.
1661 * @param listener the listener to remove
1663 public void removeTreeExpansionListener(TreeExpansionListener listener)
1665 listenerList.remove(TreeExpansionListener.class, listener);
1669 * Returns all added <code>TreeExpansionListener</code> objects.
1671 * @return an array of listeners
1673 public TreeExpansionListener[] getTreeExpansionListeners()
1675 return (TreeExpansionListener[]) getListeners(TreeExpansionListener.class);
1679 * Notifies all listeners that the tree was collapsed.
1681 * @param path the path to the node that was collapsed
1683 public void fireTreeCollapsed(TreePath path)
1685 TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1686 TreeExpansionListener[] listeners = getTreeExpansionListeners();
1688 for (int index = 0; index < listeners.length; ++index)
1689 listeners[index].treeCollapsed(event);
1693 * Notifies all listeners that the tree was expanded.
1695 * @param path the path to the node that was expanded
1697 public void fireTreeExpanded(TreePath path)
1699 TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1700 TreeExpansionListener[] listeners = getTreeExpansionListeners();
1702 for (int index = 0; index < listeners.length; ++index)
1703 listeners[index].treeExpanded(event);
1707 * Adds a <code>TreeSelctionListener</code> object to the tree.
1709 * @param listener the listener to add
1711 public void addTreeSelectionListener(TreeSelectionListener listener)
1713 listenerList.add(TreeSelectionListener.class, listener);
1717 * Removes a <code>TreeSelectionListener</code> object from the tree.
1719 * @param listener the listener to remove
1721 public void removeTreeSelectionListener(TreeSelectionListener listener)
1723 listenerList.remove(TreeSelectionListener.class, listener);
1727 * Returns all added <code>TreeSelectionListener</code> objects.
1729 * @return an array of listeners
1731 public TreeSelectionListener[] getTreeSelectionListeners()
1733 return (TreeSelectionListener[])
1734 getListeners(TreeSelectionListener.class);
1738 * Notifies all listeners when the selection of the tree changed.
1740 * @param event the event to send
1742 protected void fireValueChanged(TreeSelectionEvent event)
1744 TreeSelectionListener[] listeners = getTreeSelectionListeners();
1746 for (int index = 0; index < listeners.length; ++index)
1747 listeners[index].valueChanged(event);
1751 * Adds a <code>TreeWillExpandListener</code> object to the tree.
1753 * @param listener the listener to add
1755 public void addTreeWillExpandListener(TreeWillExpandListener listener)
1757 listenerList.add(TreeWillExpandListener.class, listener);
1761 * Removes a <code>TreeWillExpandListener</code> object from the tree.
1763 * @param listener the listener to remove
1765 public void removeTreeWillExpandListener(TreeWillExpandListener listener)
1767 listenerList.remove(TreeWillExpandListener.class, listener);
1771 * Returns all added <code>TreeWillExpandListener</code> objects.
1773 * @return an array of listeners
1775 public TreeWillExpandListener[] getTreeWillExpandListeners()
1777 return (TreeWillExpandListener[])
1778 getListeners(TreeWillExpandListener.class);
1782 * Notifies all listeners that the tree will collapse.
1784 * @param path the path to the node that will collapse
1786 public void fireTreeWillCollapse(TreePath path) throws ExpandVetoException
1788 TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1789 TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
1791 for (int index = 0; index < listeners.length; ++index)
1792 listeners[index].treeWillCollapse(event);
1796 * Notifies all listeners that the tree will expand.
1798 * @param path the path to the node that will expand
1800 public void fireTreeWillExpand(TreePath path) throws ExpandVetoException
1802 TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1803 TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
1805 for (int index = 0; index < listeners.length; ++index)
1806 listeners[index].treeWillExpand(event);
1810 * Returns the model of this <code>JTree</code> object.
1812 * @return the associated <code>TreeModel</code>
1814 public TreeModel getModel()
1816 return treeModel;
1820 * Sets the model to use in <code>JTree</code>.
1822 * @param model the <code>TreeModel</code> to use
1824 public void setModel(TreeModel model)
1826 if (treeModel == model)
1827 return;
1829 // add treeModelListener to the new model
1830 if (treeModelListener == null)
1831 treeModelListener = createTreeModelListener();
1832 if (model != null) // as setModel(null) is allowed
1833 model.addTreeModelListener(treeModelListener);
1835 TreeModel oldValue = treeModel;
1836 treeModel = model;
1838 firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model);
1839 updateUI();
1843 * Checks if this <code>JTree</code> object is editable.
1845 * @return <code>true</code> if this tree object is editable,
1846 * <code>false</code> otherwise
1848 public boolean isEditable()
1850 return editable;
1854 * Sets the <code>editable</code> property.
1856 * @param flag <code>true</code> to make this tree object editable,
1857 * <code>false</code> otherwise
1859 public void setEditable(boolean flag)
1861 if (editable == flag)
1862 return;
1864 boolean oldValue = editable;
1865 editable = flag;
1866 firePropertyChange(EDITABLE_PROPERTY, oldValue, editable);
1870 * Checks if the root element is visible.
1872 * @return <code>true</code> if the root element is visible,
1873 * <code>false</code> otherwise
1875 public boolean isRootVisible()
1877 return rootVisible;
1880 public void setRootVisible(boolean flag)
1882 if (rootVisible == flag)
1883 return;
1885 boolean oldValue = rootVisible;
1886 rootVisible = flag;
1887 firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag);
1890 public boolean getShowsRootHandles()
1892 return showsRootHandles;
1895 public void setShowsRootHandles(boolean flag)
1897 if (showsRootHandles == flag)
1898 return;
1900 boolean oldValue = showsRootHandles;
1901 showsRootHandles = flag;
1902 firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue, flag);
1905 public TreeCellEditor getCellEditor()
1907 return cellEditor;
1910 public void setCellEditor(TreeCellEditor editor)
1912 if (cellEditor == editor)
1913 return;
1915 TreeCellEditor oldValue = cellEditor;
1916 cellEditor = editor;
1917 firePropertyChange(CELL_EDITOR_PROPERTY, oldValue, editor);
1920 public TreeCellRenderer getCellRenderer()
1922 return cellRenderer;
1925 public void setCellRenderer(TreeCellRenderer newRenderer)
1927 if (cellRenderer == newRenderer)
1928 return;
1930 TreeCellRenderer oldValue = cellRenderer;
1931 cellRenderer = newRenderer;
1932 firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, newRenderer);
1935 public TreeSelectionModel getSelectionModel()
1937 return selectionModel;
1940 public void setSelectionModel(TreeSelectionModel model)
1942 if (selectionModel == model)
1943 return;
1945 if (selectionModel != null)
1946 selectionModel.removeTreeSelectionListener(selectionRedirector);
1948 TreeSelectionModel oldValue = selectionModel;
1949 selectionModel = model;
1951 if (selectionModel != null)
1952 selectionModel.addTreeSelectionListener(selectionRedirector);
1954 firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model);
1955 revalidate();
1956 repaint();
1959 public int getVisibleRowCount()
1961 return visibleRowCount;
1964 public void setVisibleRowCount(int rows)
1966 if (visibleRowCount == rows)
1967 return;
1969 int oldValue = visibleRowCount;
1970 visibleRowCount = rows;
1971 firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldValue, rows);
1974 public boolean isLargeModel()
1976 return largeModel;
1979 public void setLargeModel(boolean large)
1981 if (largeModel == large)
1982 return;
1984 boolean oldValue = largeModel;
1985 largeModel = large;
1986 firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, large);
1989 public int getRowHeight()
1991 return rowHeight;
1994 public void setRowHeight(int height)
1996 if (rowHeight == height)
1997 return;
1999 int oldValue = rowHeight;
2000 rowHeight = height;
2001 firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, height);
2004 public boolean isFixedRowHeight()
2006 return rowHeight > 0;
2009 public boolean getInvokesStopCellEditing()
2011 return invokesStopCellEditing;
2014 public void setInvokesStopCellEditing(boolean invoke)
2016 if (invokesStopCellEditing == invoke)
2017 return;
2019 boolean oldValue = invokesStopCellEditing;
2020 invokesStopCellEditing = invoke;
2021 firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY,
2022 oldValue, invoke);
2026 * @since 1.3
2028 public int getToggleClickCount()
2030 return toggleClickCount;
2034 * @since 1.3
2036 public void setToggleClickCount(int count)
2038 if (toggleClickCount == count)
2039 return;
2041 int oldValue = toggleClickCount;
2042 toggleClickCount = count;
2043 firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldValue, count);
2046 public void scrollPathToVisible(TreePath path)
2048 if (path == null)
2049 return;
2051 Object[] oPath = path.getPath();
2052 TreePath temp = new TreePath(oPath[0]);
2053 boolean stop = false;
2054 int i = 1;
2055 while (!stop)
2057 while (isVisible(temp))
2058 if (i < oPath.length)
2059 temp = temp.pathByAddingChild(oPath[i++]);
2060 else
2062 stop = true;
2063 break;
2065 makeVisible(temp);
2067 Rectangle rect = getPathBounds(path);
2068 scrollRectToVisible(rect);
2069 revalidate();
2070 repaint();
2073 public void scrollRowToVisible(int row)
2075 scrollPathToVisible(getPathForRow(row));
2078 public boolean getScrollsOnExpand()
2080 return scrollsOnExpand;
2083 public void setScrollsOnExpand(boolean scroll)
2085 if (scrollsOnExpand == scroll)
2086 return;
2088 boolean oldValue = scrollsOnExpand;
2089 scrollsOnExpand = scroll;
2090 firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue, scroll);
2093 public void setSelectionPath(TreePath path)
2095 selectionModel.setSelectionPath(path);
2098 public void setSelectionPaths(TreePath[] paths)
2100 selectionModel.setSelectionPaths(paths);
2103 public void setSelectionRow(int row)
2105 TreePath path = getPathForRow(row);
2107 if (path != null)
2108 selectionModel.setSelectionPath(path);
2111 public void setSelectionRows(int[] rows)
2113 // Make sure we have an UI so getPathForRow() does not return null.
2114 if (rows == null || getUI() == null)
2115 return;
2117 TreePath[] paths = new TreePath[rows.length];
2119 for (int i = rows.length - 1; i >= 0; --i)
2120 paths[i] = getPathForRow(rows[i]);
2122 setSelectionPaths(paths);
2125 public void setSelectionInterval(int index0, int index1)
2127 TreePath[] paths = getPathBetweenRows(index0, index1);
2129 if (paths != null)
2130 setSelectionPaths(paths);
2133 public void addSelectionPath(TreePath path)
2135 selectionModel.addSelectionPath(path);
2138 public void addSelectionPaths(TreePath[] paths)
2140 selectionModel.addSelectionPaths(paths);
2143 public void addSelectionRow(int row)
2145 TreePath path = getPathForRow(row);
2147 if (path != null)
2148 selectionModel.addSelectionPath(path);
2151 public void addSelectionRows(int[] rows)
2153 // Make sure we have an UI so getPathForRow() does not return null.
2154 if (rows == null || getUI() == null)
2155 return;
2157 TreePath[] paths = new TreePath[rows.length];
2159 for (int i = rows.length - 1; i >= 0; --i)
2160 paths[i] = getPathForRow(rows[i]);
2162 addSelectionPaths(paths);
2165 public void addSelectionInterval(int index0, int index1)
2167 TreePath[] paths = getPathBetweenRows(index0, index1);
2169 if (paths != null)
2170 addSelectionPaths(paths);
2173 public void removeSelectionPath(TreePath path)
2175 selectionModel.removeSelectionPath(path);
2178 public void removeSelectionPaths(TreePath[] paths)
2180 selectionModel.removeSelectionPaths(paths);
2183 public void removeSelectionRow(int row)
2185 TreePath path = getPathForRow(row);
2187 if (path != null)
2188 selectionModel.removeSelectionPath(path);
2191 public void removeSelectionRows(int[] rows)
2193 if (rows == null || getUI() == null)
2194 return;
2196 TreePath[] paths = new TreePath[rows.length];
2198 for (int i = rows.length - 1; i >= 0; --i)
2199 paths[i] = getPathForRow(rows[i]);
2201 removeSelectionPaths(paths);
2204 public void removeSelectionInterval(int index0, int index1)
2206 TreePath[] paths = getPathBetweenRows(index0, index1);
2208 if (paths != null)
2209 removeSelectionPaths(paths);
2212 public void clearSelection()
2214 selectionModel.clearSelection();
2215 setLeadSelectionPath(null);
2218 public TreePath getLeadSelectionPath()
2220 return leadSelectionPath;
2224 * @since 1.3
2226 public void setLeadSelectionPath(TreePath path)
2228 if (leadSelectionPath == path)
2229 return;
2231 TreePath oldValue = leadSelectionPath;
2232 leadSelectionPath = path;
2233 firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path);
2237 * @since 1.3
2239 public TreePath getAnchorSelectionPath()
2241 return anchorSelectionPath;
2245 * @since 1.3
2247 public void setAnchorSelectionPath(TreePath path)
2249 if (anchorSelectionPath == path)
2250 return;
2252 TreePath oldValue = anchorSelectionPath;
2253 anchorSelectionPath = path;
2254 firePropertyChange(ANCHOR_SELECTION_PATH_PROPERTY, oldValue, path);
2257 public int getLeadSelectionRow()
2259 return selectionModel.getLeadSelectionRow();
2262 public int getMaxSelectionRow()
2264 return selectionModel.getMaxSelectionRow();
2267 public int getMinSelectionRow()
2269 return selectionModel.getMinSelectionRow();
2272 public int getSelectionCount()
2274 return selectionModel.getSelectionCount();
2277 public TreePath getSelectionPath()
2279 return selectionModel.getSelectionPath();
2282 public TreePath[] getSelectionPaths()
2284 return selectionModel.getSelectionPaths();
2287 public int[] getSelectionRows()
2289 return selectionModel.getSelectionRows();
2292 public boolean isPathSelected(TreePath path)
2294 return selectionModel.isPathSelected(path);
2297 public boolean isRowSelected(int row)
2299 return selectionModel.isPathSelected(getPathForRow(row));
2302 public boolean isSelectionEmpty()
2304 return selectionModel.isSelectionEmpty();
2308 * Return the value of the <code>dragEnabled</code> property.
2310 * @return the value
2312 * @since 1.4
2314 public boolean getDragEnabled()
2316 return dragEnabled;
2320 * Set the <code>dragEnabled</code> property.
2322 * @param enabled new value
2324 * @since 1.4
2326 public void setDragEnabled(boolean enabled)
2328 dragEnabled = enabled;
2331 public int getRowCount()
2333 TreeUI ui = getUI();
2335 if (ui != null)
2336 return ui.getRowCount(this);
2338 return 0;
2341 public void collapsePath(TreePath path)
2345 fireTreeWillCollapse(path);
2347 catch (ExpandVetoException ev)
2349 // We do nothing if attempt has been vetoed.
2351 setExpandedState(path, false);
2352 fireTreeCollapsed(path);
2355 public void collapseRow(int row)
2357 if (row < 0 || row >= getRowCount())
2358 return;
2360 TreePath path = getPathForRow(row);
2362 if (path != null)
2363 collapsePath(path);
2366 public void expandPath(TreePath path)
2368 // Don't expand if path is null
2369 if (path == null)
2370 return;
2374 fireTreeWillExpand(path);
2376 catch (ExpandVetoException ev)
2378 // We do nothing if attempt has been vetoed.
2381 setExpandedState(path, true);
2382 fireTreeExpanded(path);
2385 public void expandRow(int row)
2387 if (row < 0 || row >= getRowCount())
2388 return;
2390 TreePath path = getPathForRow(row);
2392 if (path != null)
2393 expandPath(path);
2396 public boolean isCollapsed(TreePath path)
2398 return !isExpanded(path);
2401 public boolean isCollapsed(int row)
2403 if (row < 0 || row >= getRowCount())
2404 return false;
2406 TreePath path = getPathForRow(row);
2408 if (path != null)
2409 return isCollapsed(path);
2411 return false;
2414 public boolean isExpanded(TreePath path)
2416 if (path == null)
2417 return false;
2419 Object state = nodeStates.get(path);
2421 if ((state == null) || (state != EXPANDED))
2422 return false;
2424 TreePath parent = path.getParentPath();
2426 if (parent != null)
2427 return isExpanded(parent);
2429 return true;
2432 public boolean isExpanded(int row)
2434 if (row < 0 || row >= getRowCount())
2435 return false;
2437 TreePath path = getPathForRow(row);
2439 if (path != null)
2440 return isExpanded(path);
2442 return false;
2446 * @since 1.3
2448 public boolean getExpandsSelectedPaths()
2450 return expandsSelectedPaths;
2454 * @since 1.3
2456 public void setExpandsSelectedPaths(boolean flag)
2458 if (expandsSelectedPaths == flag)
2459 return;
2461 boolean oldValue = expandsSelectedPaths;
2462 expandsSelectedPaths = flag;
2463 firePropertyChange(EXPANDS_SELECTED_PATHS_PROPERTY, oldValue, flag);
2466 public Rectangle getPathBounds(TreePath path)
2468 TreeUI ui = getUI();
2470 if (ui == null)
2471 return null;
2473 return ui.getPathBounds(this, path);
2476 public Rectangle getRowBounds(int row)
2478 TreePath path = getPathForRow(row);
2480 if (path != null)
2481 return getPathBounds(path);
2483 return null;
2486 public boolean isEditing()
2488 TreeUI ui = getUI();
2490 if (ui != null)
2491 return ui.isEditing(this);
2493 return false;
2496 public boolean stopEditing()
2498 TreeUI ui = getUI();
2500 if (ui != null)
2501 return ui.stopEditing(this);
2503 return false;
2506 public void cancelEditing()
2508 TreeUI ui = getUI();
2510 if (ui != null)
2511 ui.cancelEditing(this);
2514 public void startEditingAtPath(TreePath path)
2516 TreeUI ui = getUI();
2518 if (ui != null)
2519 ui.startEditingAtPath(this, path);
2522 public TreePath getEditingPath()
2524 TreeUI ui = getUI();
2526 if (ui != null)
2527 return ui.getEditingPath(this);
2529 return null;
2532 public TreePath getPathForLocation(int x, int y)
2534 TreePath path = getClosestPathForLocation(x, y);
2536 if (path != null)
2538 Rectangle rect = getPathBounds(path);
2540 if ((rect != null) && rect.contains(x, y))
2541 return path;
2544 return null;
2547 public int getRowForLocation(int x, int y)
2549 TreePath path = getPathForLocation(x, y);
2551 if (path != null)
2552 return getRowForPath(path);
2554 return -1;
2557 public TreePath getClosestPathForLocation(int x, int y)
2559 TreeUI ui = getUI();
2561 if (ui != null)
2562 return ui.getClosestPathForLocation(this, x, y);
2564 return null;
2567 public int getClosestRowForLocation(int x, int y)
2569 TreePath path = getClosestPathForLocation(x, y);
2571 if (path != null)
2572 return getRowForPath(path);
2574 return -1;
2577 public Object getLastSelectedPathComponent()
2579 TreePath path = getSelectionPath();
2581 if (path != null)
2582 return path.getLastPathComponent();
2584 return null;
2587 private void doExpandParents(TreePath path, boolean state)
2589 TreePath parent = path.getParentPath();
2591 if (!isExpanded(parent) && parent != null)
2592 doExpandParents(parent, false);
2594 nodeStates.put(path, state ? EXPANDED : COLLAPSED);
2597 protected void setExpandedState(TreePath path, boolean state)
2599 if (path == null)
2600 return;
2602 doExpandParents(path, state);
2605 protected void clearToggledPaths()
2607 nodeStates.clear();
2610 protected Enumeration getDescendantToggledPaths(TreePath parent)
2612 if (parent == null)
2613 return null;
2615 Enumeration nodes = nodeStates.keys();
2616 Vector result = new Vector();
2618 while (nodes.hasMoreElements())
2620 TreePath path = (TreePath) nodes.nextElement();
2622 if (path.isDescendant(parent))
2623 result.addElement(path);
2626 return result.elements();
2629 public boolean hasBeenExpanded(TreePath path)
2631 if (path == null)
2632 return false;
2634 return nodeStates.get(path) != null;
2637 public boolean isVisible(TreePath path)
2639 if (path == null)
2640 return false;
2642 TreePath parent = path.getParentPath();
2644 if (parent == null)
2645 return true; // Is root node.
2647 return isExpanded(parent);
2650 public void makeVisible(TreePath path)
2652 if (path == null)
2653 return;
2655 expandPath(path.getParentPath());
2658 public boolean isPathEditable(TreePath path)
2660 return isEditable();
2664 * Creates and returns an instance of {@link TreeModelHandler}.
2666 * @return an instance of {@link TreeModelHandler}
2668 protected TreeModelListener createTreeModelListener()
2670 return new TreeModelHandler();
2674 * Returns a sample TreeModel that can be used in a JTree. This can be used
2675 * in Bean- or GUI-Builders to show something interesting.
2677 * @return a sample TreeModel that can be used in a JTree
2679 protected static TreeModel getDefaultTreeModel()
2681 DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root node");
2682 DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Child node 1");
2683 DefaultMutableTreeNode child11 =
2684 new DefaultMutableTreeNode("Child node 1.1");
2685 DefaultMutableTreeNode child12 =
2686 new DefaultMutableTreeNode("Child node 1.2");
2687 DefaultMutableTreeNode child13 =
2688 new DefaultMutableTreeNode("Child node 1.3");
2689 DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Child node 2");
2690 DefaultMutableTreeNode child21 =
2691 new DefaultMutableTreeNode("Child node 2.1");
2692 DefaultMutableTreeNode child22 =
2693 new DefaultMutableTreeNode("Child node 2.2");
2694 DefaultMutableTreeNode child23 =
2695 new DefaultMutableTreeNode("Child node 2.3");
2696 DefaultMutableTreeNode child24 =
2697 new DefaultMutableTreeNode("Child node 2.4");
2699 DefaultMutableTreeNode child3 = new DefaultMutableTreeNode("Child node 3");
2700 root.add(child1);
2701 root.add(child2);
2702 root.add(child3);
2703 child1.add(child11);
2704 child1.add(child12);
2705 child1.add(child13);
2706 child2.add(child21);
2707 child2.add(child22);
2708 child2.add(child23);
2709 child2.add(child24);
2710 return new DefaultTreeModel(root);
2714 * Converts the specified value to a String. This is used by the renderers
2715 * of this JTree and its nodes.
2717 * This implementation simply returns <code>value.toString()</code> and
2718 * ignores all other parameters. Subclass this method to control the
2719 * conversion.
2721 * @param value the value that is converted to a String
2722 * @param selected indicates if that value is selected or not
2723 * @param expanded indicates if that value is expanded or not
2724 * @param leaf indicates if that value is a leaf node or not
2725 * @param row the row of the node
2726 * @param hasFocus indicates if that node has focus or not
2728 public String convertValueToText(Object value, boolean selected,
2729 boolean expanded, boolean leaf, int row, boolean hasFocus)
2731 return value.toString();
2735 * A String representation of this JTree. This is intended to be used for
2736 * debugging. The returned string may be empty but may not be
2737 * <code>null</code>.
2739 * @return a String representation of this JTree
2741 public String paramString()
2743 // TODO: this is completely legal, but it would possibly be nice
2744 // to return some more content, like the tree structure, some properties
2745 // etc ...
2746 return "";
2750 * Returns all TreePath objects which are a descendants of the given path
2751 * and are exapanded at the moment of the execution of this method. If the
2752 * state of any node is beeing toggled while this method is executing this
2753 * change may be left unaccounted.
2755 * @param path The parent of this request
2757 * @return An Enumeration containing TreePath objects
2759 public Enumeration getExpandedDescendants(TreePath path)
2761 Enumeration paths = nodeStates.keys();
2762 Vector relevantPaths = new Vector();
2763 while (paths.hasMoreElements())
2765 TreePath nextPath = (TreePath) paths.nextElement();
2766 if (nodeStates.get(nextPath) == EXPANDED
2767 && path.isDescendant(nextPath))
2769 relevantPaths.add(nextPath);
2772 return relevantPaths.elements();
2776 * Returns the next table element (beginning from the row
2777 * <code>startingRow</code> that starts with <code>prefix</code>.
2778 * Searching is done in the direction specified by <code>bias</code>.
2780 * @param prefix the prefix to search for in the cell values
2781 * @param startingRow the index of the row where to start searching from
2782 * @param bias the search direction, either {@link Position.Bias#Forward} or
2783 * {@link Position.Bias#Backward}
2785 * @return the path to the found element or -1 if no such element has been
2786 * found
2788 * @throws IllegalArgumentException if prefix is <code>null</code> or
2789 * startingRow is not valid
2791 * @since 1.4
2793 public TreePath getNextMatch(String prefix, int startingRow,
2794 Position.Bias bias)
2796 if (prefix == null)
2797 throw new IllegalArgumentException("The argument 'prefix' must not be"
2798 + " null.");
2799 if (startingRow < 0)
2800 throw new IllegalArgumentException("The argument 'startingRow' must not"
2801 + " be less than zero.");
2803 int size = getRowCount();
2804 if (startingRow > size)
2805 throw new IllegalArgumentException("The argument 'startingRow' must not"
2806 + " be greater than the number of"
2807 + " elements in the TreeModel.");
2809 TreePath foundPath = null;
2810 if (bias == Position.Bias.Forward)
2812 for (int i = startingRow; i < size; i++)
2814 TreePath path = getPathForRow(i);
2815 Object o = path.getLastPathComponent();
2816 // FIXME: in the following call to convertValueToText the
2817 // last argument (hasFocus) should be done right.
2818 String item = convertValueToText(o, isRowSelected(i),
2819 isExpanded(i), treeModel.isLeaf(o),
2820 i, false);
2821 if (item.startsWith(prefix))
2823 foundPath = path;
2824 break;
2828 else
2830 for (int i = startingRow; i >= 0; i--)
2832 TreePath path = getPathForRow(i);
2833 Object o = path.getLastPathComponent();
2834 // FIXME: in the following call to convertValueToText the
2835 // last argument (hasFocus) should be done right.
2836 String item = convertValueToText(o, isRowSelected(i),
2837 isExpanded(i), treeModel.isLeaf(o), i, false);
2838 if (item.startsWith(prefix))
2840 foundPath = path;
2841 break;
2845 return foundPath;
2849 * Removes any paths in the current set of selected paths that are
2850 * descendants of <code>path</code>. If <code>includePath</code> is set
2851 * to <code>true</code> and <code>path</code> itself is selected, then
2852 * it will be removed too.
2854 * @param path the path from which selected descendants are to be removed
2855 * @param includeSelected if <code>true</code> then <code>path</code> itself
2856 * will also be remove if it's selected
2858 * @return <code>true</code> if something has been removed,
2859 * <code>false</code> otherwise
2861 * @since 1.3
2863 protected boolean removeDescendantSelectedPaths(TreePath path,
2864 boolean includeSelected)
2866 boolean removedSomething = false;
2867 TreePath[] selected = getSelectionPaths();
2868 for (int index = 0; index < selected.length; index++)
2870 if ((selected[index] == path && includeSelected)
2871 || (selected[index].isDescendant(path)))
2873 removeSelectionPath(selected[index]);
2874 removedSomething = true;
2877 return removedSomething;
2881 * Removes any descendants of the TreePaths in toRemove that have been
2882 * expanded.
2884 * @param toRemove - Enumeration of TreePaths that need to be removed from
2885 * cache of toggled tree paths.
2887 protected void removeDescendantToggledPaths(Enumeration toRemove)
2889 while (toRemove.hasMoreElements())
2891 TreePath current = (TreePath) toRemove.nextElement();
2892 Enumeration descendants = getDescendantToggledPaths(current);
2894 while (descendants.hasMoreElements())
2896 TreePath currentDes = (TreePath) descendants.nextElement();
2897 if (isExpanded(currentDes))
2898 nodeStates.remove(currentDes);
2904 * Sent when the tree has changed enough that we need to resize the bounds,
2905 * but not enough that we need to remove the expanded node set (e.g nodes
2906 * were expanded or collapsed, or nodes were inserted into the tree). You
2907 * should never have to invoke this, the UI will invoke this as it needs to.
2909 public void treeDidChange()
2911 repaint();