diff options
Diffstat (limited to 'libjava/classpath/javax/swing/JTree.java')
-rw-r--r-- | libjava/classpath/javax/swing/JTree.java | 4337 |
1 files changed, 2714 insertions, 1623 deletions
diff --git a/libjava/classpath/javax/swing/JTree.java b/libjava/classpath/javax/swing/JTree.java index bb24c7a459d..4422a193396 100644 --- a/libjava/classpath/javax/swing/JTree.java +++ b/libjava/classpath/javax/swing/JTree.java @@ -37,16 +37,32 @@ exception statement from your version. */ package javax.swing; +import java.awt.Color; +import java.awt.Cursor; import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.FocusListener; +import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; +import java.util.Locale; import java.util.Vector; import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleComponent; import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.accessibility.AccessibleValue; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeModelEvent; @@ -57,7 +73,6 @@ import javax.swing.event.TreeWillExpandListener; import javax.swing.plaf.TreeUI; import javax.swing.text.Position; import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.ExpandVetoException; @@ -68,1754 +83,2830 @@ import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; -public class JTree - extends JComponent - implements Scrollable, Accessible +public class JTree extends JComponent implements Scrollable, Accessible { - /** - * Listens to the model of the JTree and updates the property - * <code>expandedState</code> if nodes are removed or changed. - */ - protected class TreeModelHandler - implements - TreeModelListener - { - - /** - * Creates a new instance of TreeModelHandler. - */ - protected TreeModelHandler() - { - } - - /** - * Notifies when a node has changed in some ways. This does not include - * that a node has changed its location or changed it's children. It - * only means that some attributes of the node have changed that might - * affect its presentation. - * - * This method is called after the actual change occured. - * - * @param ev the TreeModelEvent describing the change - */ - public void treeNodesChanged(TreeModelEvent ev) - { - // nothing to do here - } - - /** - * Notifies when a node is inserted into the tree. - * - * This method is called after the actual change occured. - * - * @param ev the TreeModelEvent describing the change - */ - public void treeNodesInserted(TreeModelEvent ev) - { - // nothing to do here - } - - /** - * Notifies when a node is removed from the tree. - * - * This method is called after the actual change occured. - * - * @param ev the TreeModelEvent describing the change - */ - public void treeNodesRemoved(TreeModelEvent ev) - { - // TODO: The API docs suggest that this method should do something - // but I cannot really see what has to be done here ... - } - - /** - * Notifies when the structure of the tree is changed. - * - * This method is called after the actual change occured. - * - * @param ev the TreeModelEvent describing the change - */ - public void treeStructureChanged(TreeModelEvent ev) - { - // set state of new path - TreePath path = ev.getTreePath(); - setExpandedState(path, isExpanded(path)); - } - } // TreeModelHandler - - /** - * This redirects TreeSelectionEvents and rewrites the source of it to be - * this JTree. This is typically done when the tree model generates an - * event, but the JTree object associated with that model should be listed - * as the actual source of the event. - */ - protected class TreeSelectionRedirector - implements - TreeSelectionListener, - Serializable - { - /** The serial version UID. */ - private static final long serialVersionUID = -3505069663646241664L; - - /** - * Creates a new instance of TreeSelectionRedirector - */ - protected TreeSelectionRedirector() - { - } - - /** - * Notifies when the tree selection changes. - * - * @param ev the TreeSelectionEvent that describes the change - */ - public void valueChanged(TreeSelectionEvent ev) - { - TreeSelectionEvent rewritten = (TreeSelectionEvent) ev - .cloneWithSource(JTree.this); - fireValueChanged(rewritten); - JTree.this.repaint(); - } - } // TreeSelectionRedirector - - /** - * A TreeModel that does not allow anything to be selected. + + /** + * This class implements accessibility support for the JTree class. It + * provides an implementation of the Java Accessibility API appropriate + * to tree user-interface elements. + */ + protected class AccessibleJTree extends JComponent.AccessibleJComponent + implements AccessibleSelection, TreeSelectionListener, TreeModelListener, + TreeExpansionListener + { + + /** + * This class implements accessibility support for the JTree child. It provides + * an implementation of the Java Accessibility API appropriate to tree nodes. + */ + protected class AccessibleJTreeNode extends AccessibleContext + implements Accessible, AccessibleComponent, AccessibleSelection, + AccessibleAction + { + + private JTree tree; + private TreePath tp; + private Accessible acc; + private AccessibleStateSet states; + private Vector selectionList; + private Vector actionList; + private TreeModel mod; + private Cursor cursor; + + /** + * Constructs an AccessibleJTreeNode + * + * @param t - the current tree + * @param p - the current path to be dealt with + * @param ap - the accessible object to use + */ + public AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) + { + states = new AccessibleStateSet(); + selectionList = new Vector(); + actionList = new Vector(); + mod = tree.getModel(); + cursor = JTree.this.getCursor(); + + tree = t; + tp = p; + acc = ap; + + // Add all the children of this path that may already be + // selected to the selection list. + TreePath[] selected = tree.getSelectionPaths(); + for (int i = 0; i < selected.length; i++) + { + TreePath sel = selected[i]; + if ((sel.getParentPath()).equals(tp)) + selectionList.add(sel); + } + + // Add all the actions available for a node to + // the action list. + actionList.add("EXPAND"); + actionList.add("COLLAPSE"); + actionList.add("EDIT"); + actionList.add("SELECT"); + actionList.add("DESELECT"); + } + + /** + * Adds the specified selected item in the object to the object's + * selection. + * + * @param i - the i-th child of this node. + */ + public void addAccessibleSelection(int i) + { + if (mod != null) + { + Object child = mod.getChild(tp.getLastPathComponent(), i); + if (child != null) + { + if (!states.contains(AccessibleState.MULTISELECTABLE)) + clearAccessibleSelection(); + selectionList.add(child); + tree.addSelectionPath(tp.pathByAddingChild(child)); + } + } + } + + /** + * Adds the specified focus listener to receive focus events + * from this component. + * + * @param l - the new focus listener + */ + public void addFocusListener(FocusListener l) + { + tree.addFocusListener(l); + } + + /** + * Add a PropertyChangeListener to the listener list. + * + * @param l - the new property change listener + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + // Nothing to do here. + } + + /** + * Clears the selection in the object, so that nothing in the + * object is selected. + */ + public void clearAccessibleSelection() + { + selectionList.clear(); + } + + /** + * Checks whether the specified point is within this object's + * bounds, where the point's x and y coordinates are defined to be + * relative to the coordinate system of the object. + * + * @param p - the point to check + * @return true if p is in the bounds + */ + public boolean contains(Point p) + { + return getBounds().contains(p); + } + + /** + * Perform the specified Action on the tree node. + * + * @param i - the i-th action to perform + * @return true if the the action was performed; else false. + */ + public boolean doAccessibleAction(int i) + { + if (i >= actionList.size() || i < 0) + return false; + + if (actionList.get(i).equals("EXPAND")) + tree.expandPath(tp); + else if (actionList.get(i).equals("COLLAPSE")) + tree.collapsePath(tp); + else if (actionList.get(i).equals("SELECT")) + tree.addSelectionPath(tp); + else if (actionList.get(i).equals("DESELECT")) + tree.removeSelectionPath(tp); + else if (actionList.get(i).equals("EDIT")) + tree.startEditingAtPath(tp); + else + return false; + return true; + } + + /** + * Get the AccessibleAction associated with this object. + * + * @return the action + */ + public AccessibleAction getAccessibleAction() + { + return this; + } + + /** + * Returns the number of accessible actions available in this tree node. + * + * @return the number of actions + */ + public int getAccessibleActionCount() + { + return actionList.size(); + } + + /** + * Return a description of the specified action of the tree node. + * + * @param i - the i-th action's description + * @return a description of the action + */ + public String getAccessibleActionDescription(int i) + { + if (i < 0 || i >= actionList.size()) + return (actionList.get(i)).toString(); + return super.getAccessibleDescription(); + } + + /** + * Returns the Accessible child, if one exists, contained at the + * local coordinate Point. + * + * @param p - the point of the accessible + * @return the accessible at point p if it exists + */ + public Accessible getAccessibleAt(Point p) + { + TreePath acc = tree.getClosestPathForLocation(p.x, p.y); + if (acc != null) + return new AccessibleJTreeNode(tree, acc, this); + return null; + } + + /** + * Return the specified Accessible child of the object. + * + * @param i - the i-th child of the current path + * @return the child if it exists + */ + public Accessible getAccessibleChild(int i) + { + if (mod != null) + { + Object child = mod.getChild(tp.getLastPathComponent(), i); + if (child != null) + return new AccessibleJTreeNode(tree, tp.pathByAddingChild(child), + acc); + } + return null; + } + + /** + * Returns the number of accessible children in the object. + * + * @return the number of children the current node has + */ + public int getAccessibleChildrenCount() + { + TreeModel mod = getModel(); + if (mod != null) + return mod.getChildCount(tp.getLastPathComponent()); + return 0; + } + + /** + * Get the AccessibleComponent associated with this object. + * + * @return the accessible component if it is supported. + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } + + /** + * Get the AccessibleContext associated with this tree node. + * + * @return an instance of this class + */ + public AccessibleContext getAccessibleContext() + { + return this; + } + + /** + * Get the accessible description of this object. + * + * @return the accessible description + */ + public String getAccessibleDescription() + { + return super.getAccessibleDescription(); + } + + /** + * Get the index of this object in its accessible parent. + * + * @return the index of this in the parent. + */ + public int getAccessibleIndexInParent() + { + AccessibleContext parent = getAccessibleParent().getAccessibleContext(); + if (parent != null) + for (int i = 0; i < parent.getAccessibleChildrenCount(); i++) + { + if ((parent.getAccessibleChild(i)).equals(this)) + return i; + } + return -1; + } + + /** + * Get the accessible name of this object. + * + * @return the accessible name + */ + public String getAccessibleName() + { + return super.getAccessibleName(); + } + + /** + * Get the Accessible parent of this object. + * + * @return the accessible parent if it exists. + */ + public Accessible getAccessibleParent() + { + return super.getAccessibleParent(); + } + + /** + * Get the role of this object. + * + * @return the accessible role + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleJTree.this.getAccessibleRole(); + } + + /** + * Get the AccessibleSelection associated with this object if one exists. + * + * @return the accessible selection for this. + */ + public AccessibleSelection getAccessibleSelection() + { + return this; + } + + /** + * Returns an Accessible representing the specified selected item + * in the object. + * + * @return the accessible representing a certain selected item. + */ + public Accessible getAccessibleSelection(int i) + { + if (i > 0 && i < getAccessibleSelectionCount()) + return new AccessibleJTreeNode(tree, + tp.pathByAddingChild(selectionList.get(i)), acc); + return null; + } + + /** + * Returns the number of items currently selected. + * + * @return the number of items selected. + */ + public int getAccessibleSelectionCount() + { + return selectionList.size(); + } + + /** + * Get the state set of this object. + * + * @return the state set for this object + */ + public AccessibleStateSet getAccessibleStateSet() + { + if (isVisible()) + states.add(AccessibleState.VISIBLE); + if (tree.isCollapsed(tp)) + states.add(AccessibleState.COLLAPSED); + if (tree.isEditable()) + states.add(AccessibleState.EDITABLE); + if (mod != null && + !mod.isLeaf(tp.getLastPathComponent())) + states.add(AccessibleState.EXPANDABLE); + if (tree.isExpanded(tp)) + states.add(AccessibleState.EXPANDED); + if (isFocusable()) + states.add(AccessibleState.FOCUSABLE); + if (hasFocus()) + states.add(AccessibleState.FOCUSED); + if (tree.getSelectionModel().getSelectionMode() != + TreeSelectionModel.SINGLE_TREE_SELECTION) + states.add(AccessibleState.MULTISELECTABLE); + if (tree.isOpaque()) + states.add(AccessibleState.OPAQUE); + if (tree.isPathSelected(tp)) + states.add(AccessibleState.SELECTED); + if (isShowing()) + states.add(AccessibleState.SHOWING); + + states.add(AccessibleState.SELECTABLE); + return states; + } + + /** + * Get the AccessibleText associated with this object if one exists. + * + * @return the accessible text + */ + public AccessibleText getAccessibleText() + { + return super.getAccessibleText(); + } + + /** + * Get the AccessibleValue associated with this object if one exists. + * + * @return the accessible value if it exists + */ + public AccessibleValue getAccessibleValue() + { + return super.getAccessibleValue(); + } + + /** + * Get the background color of this object. + * + * @return the color of the background. + */ + public Color getBackground() + { + return tree.getBackground(); + } + + /** + * Gets the bounds of this object in the form of a Rectangle object. + * + * @return the bounds of the current node. + */ + public Rectangle getBounds() + { + return tree.getPathBounds(tp); + } + + /** + * Gets the Cursor of this object. + * + * @return the cursor for the current node + */ + public Cursor getCursor() + { + return cursor; + } + + /** + * Gets the Font of this object. + * + * @return the font for the current node + */ + public Font getFont() + { + return tree.getFont(); + } + + /** + * Gets the FontMetrics of this object. + * + * @param f - the current font. + * @return the font metrics for the given font. + */ + public FontMetrics getFontMetrics(Font f) + { + return tree.getFontMetrics(f); + } + + /** + * Get the foreground color of this object. + * + * @return the foreground for this object. + */ + public Color getForeground() + { + return tree.getForeground(); + } + + /** + * Gets the locale of the component. + * + * @return the locale of the component. + */ + public Locale getLocale() + { + return tree.getLocale(); + } + + /** + * Gets the location of the object relative to the + * parent in the form of a point specifying the object's + * top-left corner in the screen's coordinate space. + * + * @return the location of the current node. + */ + public Point getLocation() + { + return getLocationInJTree(); + } + + /** + * Returns the location in the tree. + * + * @return the location in the JTree. + */ + protected Point getLocationInJTree() + { + Rectangle bounds = tree.getPathBounds(tp); + return new Point(bounds.x, bounds.y); + } + + /** + * Returns the location of the object on the screen. + * + * @return the location of the object on the screen. + */ + public Point getLocationOnScreen() + { + Point loc = getLocation(); + SwingUtilities.convertPointToScreen(loc, tree); + return loc; + } + + /** + * Returns the size of this object in the form of a Dimension object. + * + * @return the size of the object + */ + public Dimension getSize() + { + Rectangle b = getBounds(); + return b.getSize(); + } + + /** + * Returns true if the current child of this object is selected. + * + * @param i - the child of the current node + * @return true if the child is selected. + */ + public boolean isAccessibleChildSelected(int i) + { + Object child = mod.getChild(tp.getLastPathComponent(), i); + if (child != null) + return tree.isPathSelected(tp.pathByAddingChild(child)); + return false; + } + + /** + * Determines if the object is enabled. + * + * @return true if the tree is enabled + */ + public boolean isEnabled() + { + return tree.isEnabled(); + } + + /** + * Returns whether this object can accept focus or not. + * + * @return true, it is always focus traversable + */ + public boolean isFocusTraversable() + { + return true; + } + + /** + * Determines if the object is showing. + * + * @return true if the object is visible and the + * parent is visible. + */ + public boolean isShowing() + { + return isVisible() && tree.isShowing(); + } + + /** + * Determines if the object is visible. + * + * @return true if the object is visible. + */ + public boolean isVisible() + { + return tree.isVisible(tp); + } + + /** + * Removes the specified selected item in the object from the + * object's selection. + * + * @param i - the specified item to remove + */ + public void removeAccessibleSelection(int i) + { + if (mod != null) + { + Object child = mod.getChild(tp.getLastPathComponent(), i); + if (child != null) + { + if (!states.contains(AccessibleState.MULTISELECTABLE)) + clearAccessibleSelection(); + if (selectionList.contains(child)) + { + selectionList.remove(child); + tree.removeSelectionPath(tp.pathByAddingChild(child)); + } + } + } + } + + /** + * Removes the specified focus listener so it no longer receives focus + * events from this component. + * + * @param l - the focus listener to remove + */ + public void removeFocusListener(FocusListener l) + { + tree.removeFocusListener(l); + } + + /** + * Remove a PropertyChangeListener from the listener list. + * + * @param l - the property change listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + // Nothing to do here. + } + + /** + * Requests focus for this object. + */ + public void requestFocus() + { + tree.requestFocus(); + } + + /** + * Causes every selected item in the object to be selected if the object + * supports multiple selections. + */ + public void selectAllAccessibleSelection() + { + Object parent = tp.getLastPathComponent(); + if (mod != null) + { + for (int i = 0; i < mod.getChildCount(parent); i++) + { + Object child = mod.getChild(parent, i); + if (child != null) + { + if (!states.contains(AccessibleState.MULTISELECTABLE)) + clearAccessibleSelection(); + if (selectionList.contains(child)) + { + selectionList.add(child); + tree.addSelectionPath(tp.pathByAddingChild(child)); + } + } + } + } + } + + /** + * Set the accessible description of this object. + * + * @param s - the string to set the accessible description to. + */ + public void setAccessibleDescription(String s) + { + super.setAccessibleDescription(s); + } + + /** + * Set the localized accessible name of this object. + * + * @param s - the string to set the accessible name to. + */ + public void setAccessibleName(String s) + { + super.setAccessibleName(s); + } + + /** + * Set the background color of this object. + * + * @param c - the color to set the background to. + */ + public void setBackground(Color c) + { + // Nothing to do here. + } + + /** + * Sets the bounds of this object in the form of a Rectangle object. + * + * @param r - the bounds to set the object o + */ + public void setBounds(Rectangle r) + { + // Nothing to do here. + } + + /** + * Sets the Cursor of this object. + * + * @param c - the new cursor + */ + public void setCursor(Cursor c) + { + cursor = c; + } + + /** + * Sets the enabled state of the object. + * + * @param b - boolean to enable or disable object + */ + public void setEnabled(boolean b) + { + // Nothing to do here. + } + + /** + * Sets the Font of this object. + * + * @param f - the new font. + */ + public void setFont(Font f) + { + // Nothing to do here. + } + + /** + * Sets the foreground color of this object. + * + * @param c - the new foreground color. + */ + public void setForeground(Color c) + { + // Nothing to do here. + } + + /** + * Sets the location of the object relative to the parent. + * + * @param p - the new location for the object. + */ + public void setLocation(Point p) + { + // Nothing to do here. + } + + /** + * Resizes this object so that it has width and height. + * + * @param d - the new size for the object. + */ + public void setSize(Dimension d) + { + // Nothing to do here. + } + + /** + * Sets the visible state of the object. + * + * @param b - sets the objects visibility. + */ + public void setVisible(boolean b) + { + // Nothing to do here. + } + } + + /** + * Constructor + */ + public AccessibleJTree() + { + // Nothing to do here. + } + + /** + * Adds the specified selected item in the object to the object's selection. + * + * @param i - the row to add to the tree's selection + */ + public void addAccessibleSelection(int i) + { + addSelectionInterval(i, i); + } + + /** + * Clears the selection in the object, so that nothing in the object is selected. + */ + public void clearAccessibleSelection() + { + clearSelection(); + } + + /** + * Fire a visible data property change notification. + */ + public void fireVisibleDataPropertyChange() + { + treeDidChange(); + } + + /** + * Returns the Accessible child, if one exists, contained at the local + * coordinate Point. + * + * @param p - the point of the accessible to get. + * @return the accessible at point p. + */ + public Accessible getAccessibleAt(Point p) + { + TreePath tp = getClosestPathForLocation(p.x, p.y); + if (tp != null) + return new AccessibleJTreeNode(JTree.this, tp, null); + return null; + } + + /** + * Return the nth Accessible child of the object. + * + * @param i - the accessible child to get + * @return the i-th child + */ + public Accessible getAccessibleChild(int i) + { + return null; + } + + /** + * Returns the number of top-level children nodes of this JTree. + * + * @return the number of top-level children + */ + public int getAccessibleChildrenCount() + { + TreeModel model = getModel(); + if (model != null) + return model.getChildCount(model.getRoot()); + return 0; + } + + /** + * Get the index of this object in its accessible parent. + * + * @return the index of this object. + */ + public int getAccessibleIndexInParent() + { + return 0; + } + + /** + * Get the role of this object. + * + * @return the role of this object + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.TREE; + } + + /** + * Get the AccessibleSelection associated with this object. + * + * @return the accessible selection of the tree + */ + public AccessibleSelection getAccessibleSelection() + { + TreeModel mod = getModel(); + if (mod != null) + return (new AccessibleJTreeNode(JTree.this, + new TreePath(mod.getRoot()), null)).getAccessibleSelection(); + return null; + } + + /** + * Returns an Accessible representing the specified selected item in the object. + * + * @return the i-th accessible in the selection + */ + public Accessible getAccessibleSelection(int i) + { + TreeModel mod = getModel(); + if (mod != null) + return (new AccessibleJTreeNode(JTree.this, + new TreePath(mod.getRoot()), null)).getAccessibleSelection(i); + return null; + } + + /** + * Returns the number of items currently selected. + * + * @return the number of selected accessibles. + */ + public int getAccessibleSelectionCount() + { + return getSelectionCount(); + } + + /** + * Returns true if the current child of this object is selected. + * + * @param i - the child of this object + * @return true if the i-th child is selected. + */ + public boolean isAccessibleChildSelected(int i) + { + // Nothing to do here. + return false; + } + + /** + * Removes the specified selected item in the object from the object's + * selection. + * + * @param i - the i-th selected item to remove + */ + public void removeAccessibleSelection(int i) + { + removeSelectionInterval(i, i); + } + + /** + * Causes every selected item in the object to be selected if the object + * supports multiple selections. + */ + public void selectAllAccessibleSelection() + { + if (getSelectionModel().getSelectionMode() != + TreeSelectionModel.SINGLE_TREE_SELECTION) + addSelectionInterval(0, getVisibleRowCount()); + } + + /** + * Tree Collapsed notification + * + * @param e - the event + */ + public void treeCollapsed(TreeExpansionEvent e) + { + fireTreeCollapsed(e.getPath()); + } + + /** + * Tree Model Expansion notification. + * + * @param e - the event + */ + public void treeExpanded(TreeExpansionEvent e) + { + fireTreeExpanded(e.getPath()); + } + + /** + * Tree Model Node change notification. + * + * @param e - the event + */ + public void treeNodesChanged(TreeModelEvent e) + { + // Nothing to do here. + } + + /** + * Tree Model Node change notification. + * + * @param e - the event + */ + public void treeNodesInserted(TreeModelEvent e) + { + // Nothing to do here. + } + + /** + * Tree Model Node change notification. + * + * @param e - the event + */ + public void treeNodesRemoved(TreeModelEvent e) + { + // Nothing to do here. + } + + /** + * Tree Model structure change change notification. + * + * @param e - the event + */ + public void treeStructureChanged(TreeModelEvent e) + { + // Nothing to do here. + } + + /** + * Tree Selection Listener value change method. + * + * @param e - the event + */ + public void valueChanged(TreeSelectionEvent e) + { + fireValueChanged(e); + } + } + + public static class DynamicUtilTreeNode extends DefaultMutableTreeNode + { + protected Object childValue; + + protected boolean loadedChildren; + + /** + * Currently not set or used by this class. It might be set and used in + * later versions of this class. + */ + protected boolean hasChildren; + + public DynamicUtilTreeNode(Object value, Object children) + { + super(value); + childValue = children; + loadedChildren = false; + } + + public int getChildCount() + { + loadChildren(); + return super.getChildCount(); + } + + protected void loadChildren() + { + if (!loadedChildren) + { + createChildren(this, childValue); + loadedChildren = true; + } + } + + public Enumeration children() + { + loadChildren(); + return super.children(); + } + + /** + * Returns the child node at position <code>pos</code>. Subclassed + * here to load the children if necessary. + * + * @param pos the position of the child node to fetch + * + * @return the childnode at the specified position + */ + public TreeNode getChildAt(int pos) + { + loadChildren(); + return super.getChildAt(pos); + } + + public boolean isLeaf() + { + return (childValue == null || !(childValue instanceof Hashtable + || childValue instanceof Vector || childValue.getClass() + .isArray())); + } + + public static void createChildren(DefaultMutableTreeNode parent, + Object children) + { + if (children instanceof Hashtable) + { + Hashtable tab = (Hashtable) children; + Enumeration e = tab.keys(); + while (e.hasMoreElements()) + { + Object key = e.nextElement(); + Object val = tab.get(key); + parent.add(new DynamicUtilTreeNode(key, val)); + } + } + else if (children instanceof Vector) + { + Iterator i = ((Vector) children).iterator(); + while (i.hasNext()) + { + Object n = i.next(); + parent.add(new DynamicUtilTreeNode(n, n)); + } + } + else if (children != null && children.getClass().isArray()) + { + Object[] arr = (Object[]) children; + for (int i = 0; i < arr.length; ++i) + parent.add(new DynamicUtilTreeNode(arr[i], arr[i])); + } + } + } + + /** + * Listens to the model of the JTree and updates the property + * <code>expandedState</code> if nodes are removed or changed. + */ + protected class TreeModelHandler implements TreeModelListener + { + + /** + * Creates a new instance of TreeModelHandler. + */ + protected TreeModelHandler() + { + // Nothing to do here. + } + + /** + * Notifies when a node has changed in some ways. This does not include + * that a node has changed its location or changed it's children. It + * only means that some attributes of the node have changed that might + * affect its presentation. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeNodesChanged(TreeModelEvent ev) + { + // Nothing to do here. + } + + /** + * Notifies when a node is inserted into the tree. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeNodesInserted(TreeModelEvent ev) + { + // nothing to do here + } + + /** + * Notifies when a node is removed from the tree. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change */ - protected static class EmptySelectionModel - extends - DefaultTreeSelectionModel - { - /** The serial version UID. */ - private static final long serialVersionUID = -5815023306225701477L; - - /** - * The shared instance of this model. - */ - protected static final EmptySelectionModel sharedInstance = new EmptySelectionModel(); - - /** - * Creates a new instance of EmptySelectionModel. - */ - protected EmptySelectionModel() - { - } - - /** - * Returns the shared instance of EmptySelectionModel. - * - * @return the shared instance of EmptySelectionModel - */ - public static EmptySelectionModel sharedInstance() - { - return sharedInstance; - } - - /** - * This catches attempts to set a selection and sets nothing instead. - * - * @param paths not used here - */ - public void setSelectionPaths(TreePath[] paths) - { - // we don't allow selections in this class - } - - /** - * This catches attempts to add something to the selection. - * - * @param paths not used here - */ - public void addSelectionPaths(TreePath[] paths) - { - // we don't allow selections in this class - } - - /** - * This catches attempts to remove something from the selection. - * - * @param paths not used here - */ - public void removeSelectionPaths(TreePath[] paths) - { - // we don't allow selections in this class - } - }// EmptySelectionModel - - private static final long serialVersionUID = 7559816092864483649L; - public static final String CELL_EDITOR_PROPERTY = "cellEditor"; - public static final String CELL_RENDERER_PROPERTY = "cellRenderer"; - public static final String EDITABLE_PROPERTY = "editable"; - public static final String INVOKES_STOP_CELL_EDITING_PROPERTY = "invokesStopCellEditing"; - public static final String LARGE_MODEL_PROPERTY = "largeModel"; - public static final String ROOT_VISIBLE_PROPERTY = "rootVisible"; - public static final String ROW_HEIGHT_PROPERTY = "rowHeight"; - public static final String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand"; - public static final String SELECTION_MODEL_PROPERTY = "selectionModel"; - public static final String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles"; - public static final String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount"; - public static final String TREE_MODEL_PROPERTY = "model"; - public static final String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount"; + public void treeNodesRemoved(TreeModelEvent ev) + { + // TODO: The API docs suggest that this method should do something + // but I cannot really see what has to be done here ... + } - /** @since 1.3 */ - public static final String ANCHOR_SELECTION_PATH_PROPERTY = "anchorSelectionPath"; + /** + * Notifies when the structure of the tree is changed. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeStructureChanged(TreeModelEvent ev) + { + // Set state of new path. + TreePath path = ev.getTreePath(); + setExpandedState(path, isExpanded(path)); + } + } - /** @since 1.3 */ - public static final String LEAD_SELECTION_PATH_PROPERTY = "leadSelectionPath"; + /** + * This redirects TreeSelectionEvents and rewrites the source of it to be + * this JTree. This is typically done when the tree model generates an + * event, but the JTree object associated with that model should be listed + * as the actual source of the event. + */ + protected class TreeSelectionRedirector implements TreeSelectionListener, + Serializable + { + /** The serial version UID. */ + private static final long serialVersionUID = -3505069663646241664L; + + /** + * Creates a new instance of TreeSelectionRedirector + */ + protected TreeSelectionRedirector() + { + // Nothing to do here. + } + + /** + * Notifies when the tree selection changes. + * + * @param ev the TreeSelectionEvent that describes the change + */ + public void valueChanged(TreeSelectionEvent ev) + { + TreeSelectionEvent rewritten = + (TreeSelectionEvent) ev.cloneWithSource(JTree.this); + fireValueChanged(rewritten); + JTree.this.repaint(); + } + } + + /** + * A TreeModel that does not allow anything to be selected. + */ + protected static class EmptySelectionModel extends DefaultTreeSelectionModel + { + /** The serial version UID. */ + private static final long serialVersionUID = -5815023306225701477L; + + /** + * The shared instance of this model. + */ + protected static final EmptySelectionModel sharedInstance = + new EmptySelectionModel(); + + /** + * Creates a new instance of EmptySelectionModel. + */ + protected EmptySelectionModel() + { + // Nothing to do here. + } + + /** + * Returns the shared instance of EmptySelectionModel. + * + * @return the shared instance of EmptySelectionModel + */ + public static EmptySelectionModel sharedInstance() + { + return sharedInstance; + } + + /** + * This catches attempts to set a selection and sets nothing instead. + * + * @param paths not used here + */ + public void setSelectionPaths(TreePath[] paths) + { + // We don't allow selections in this class. + } + + /** + * This catches attempts to add something to the selection. + * + * @param paths not used here + */ + public void addSelectionPaths(TreePath[] paths) + { + // We don't allow selections in this class. + } + + /** + * This catches attempts to remove something from the selection. + * + * @param paths not used here + */ + public void removeSelectionPaths(TreePath[] paths) + { + // We don't allow selections in this class. + } + } + + private static final long serialVersionUID = 7559816092864483649L; + + public static final String CELL_EDITOR_PROPERTY = "cellEditor"; + + public static final String CELL_RENDERER_PROPERTY = "cellRenderer"; + + public static final String EDITABLE_PROPERTY = "editable"; + + public static final String INVOKES_STOP_CELL_EDITING_PROPERTY = + "invokesStopCellEditing"; + + public static final String LARGE_MODEL_PROPERTY = "largeModel"; + + public static final String ROOT_VISIBLE_PROPERTY = "rootVisible"; + + public static final String ROW_HEIGHT_PROPERTY = "rowHeight"; + + public static final String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand"; + + public static final String SELECTION_MODEL_PROPERTY = "selectionModel"; + + public static final String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles"; + + public static final String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount"; + + public static final String TREE_MODEL_PROPERTY = "model"; + + public static final String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount"; + + /** @since 1.3 */ + public static final String ANCHOR_SELECTION_PATH_PROPERTY = + "anchorSelectionPath"; /** @since 1.3 */ - public static final String EXPANDS_SELECTED_PATHS_PROPERTY = "expandsSelectedPaths"; - private static final Object EXPANDED = new Object(); - private static final Object COLLAPSED = new Object(); - private boolean dragEnabled; - private boolean expandsSelectedPaths; - private TreePath anchorSelectionPath; - private TreePath leadSelectionPath; - - /* - * This contains the state of all nodes in the tree. Al/ entries map the - * TreePath of a note to to its state. Valid states are EXPANDED and - * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED. - */ - private Hashtable nodeStates = new Hashtable(); - protected transient TreeCellEditor cellEditor; - protected transient TreeCellRenderer cellRenderer; - protected boolean editable; - protected boolean invokesStopCellEditing; - protected boolean largeModel; - protected boolean rootVisible; - protected int rowHeight; - protected boolean scrollsOnExpand; - protected transient TreeSelectionModel selectionModel; - protected boolean showsRootHandles; - protected int toggleClickCount; - protected transient TreeModel treeModel; - protected int visibleRowCount; - - /** - * Handles TreeModelEvents to update the expandedState. - */ - protected transient TreeModelListener treeModelListener; + public static final String LEAD_SELECTION_PATH_PROPERTY = "leadSelectionPath"; - /** - * Redirects TreeSelectionEvents so that the source is this JTree. - */ - protected TreeSelectionRedirector selectionRedirector = - new TreeSelectionRedirector(); + /** @since 1.3 */ + public static final String EXPANDS_SELECTED_PATHS_PROPERTY = + "expandsSelectedPaths"; - /** - * Creates a new <code>JTree</code> object. - */ - public JTree() - { - this(createTreeModel(null)); - } - - /** - * Creates a new <code>JTree</code> object. - * - * @param value the initial nodes in the tree - */ - public JTree(Hashtable value) - { - this(createTreeModel(value)); - } - - /** - * Creates a new <code>JTree</code> object. - * - * @param value the initial nodes in the tree - */ - public JTree(Object[] value) - { - this(createTreeModel(value)); - } - - /** - * Creates a new <code>JTree</code> object. - * - * @param model the model to use - */ - public JTree(TreeModel model) - { - setModel(model); - setSelectionModel(EmptySelectionModel.sharedInstance()); - setCellRenderer(new DefaultTreeCellRenderer()); - updateUI(); - } - - /** - * Creates a new <code>JTree</code> object. - * - * @param root the root node - */ - public JTree(TreeNode root) - { - this(root, false); - } - - /** - * Creates a new <code>JTree</code> object. - * - * @param root the root node - * @param asksAllowChildren if false, all nodes without children are leaf - * nodes. If true, only nodes that do not allow children are leaf - * nodes. - */ - public JTree(TreeNode root, boolean asksAllowChildren) - { - this(new DefaultTreeModel(root, asksAllowChildren)); - } - - /** - * Creates a new <code>JTree</code> object. - * - * @param value the initial nodes in the tree - */ - public JTree(Vector value) - { - this(createTreeModel(value)); - } - - public static class DynamicUtilTreeNode - extends - DefaultMutableTreeNode - { - protected Object childValue; - protected boolean loadedChildren; - - /** - * Currently not set or used by this class. It might be set and used in - * later versions of this class. - */ - protected boolean hasChildren; - - public DynamicUtilTreeNode(Object value, Object children) - { - super(value); - childValue = children; - loadedChildren = false; - } - - public int getChildCount() - { - loadChildren(); - return super.getChildCount(); - } - - protected void loadChildren() - { - if (!loadedChildren) - { - createChildren(this, childValue); - loadedChildren = true; - } - } - - public Enumeration children() - { - loadChildren(); - return super.children(); - } - - /** - * Returns the child node at position <code>pos</code>. Subclassed - * here to load the children if necessary. - * - * @param pos the position of the child node to fetch - * - * @return the childnode at the specified position - */ - public TreeNode getChildAt(int pos) - { - loadChildren(); - return super.getChildAt(pos); - } - - public boolean isLeaf() - { - return (childValue == null || !(childValue instanceof Hashtable - || childValue instanceof Vector || childValue.getClass() - .isArray())); - } - - public static void createChildren(DefaultMutableTreeNode parent, - Object children) - { - if (children instanceof Hashtable) - { - Hashtable tab = (Hashtable) children; - Enumeration e = tab.keys(); - while (e.hasMoreElements()) - { - Object key = e.nextElement(); - Object val = tab.get(key); - parent.add(new DynamicUtilTreeNode(key, val)); - } - } else if (children instanceof Vector) - { - Iterator i = ((Vector) children).iterator(); - while (i.hasNext()) - { - Object n = i.next(); - parent.add(new DynamicUtilTreeNode(n, n)); - } - } else if (children != null && children.getClass().isArray()) - { - Object[] arr = (Object[]) children; - for (int i = 0; i < arr.length; ++i) - parent.add(new DynamicUtilTreeNode(arr[i], arr[i])); - } - } - } - - public int getRowForPath(TreePath path) - { - TreeUI ui = getUI(); - - if (ui != null) - return ui.getRowForPath(this, path); - - return -1; - } - - public TreePath getPathForRow(int row) - { - TreeUI ui = getUI(); - return ui != null ? ui.getPathForRow(this, row) : null; - } - - protected TreePath[] getPathBetweenRows(int index0, int index1) - { - TreeUI ui = getUI(); - - if (ui == null) - return null; - - int minIndex = Math.min(index0, index1); - int maxIndex = Math.max(index0, index1); - TreePath[] paths = new TreePath[maxIndex - minIndex + 1]; - - for (int i = minIndex; i <= maxIndex; ++i) - paths[i - minIndex] = ui.getPathForRow(this, i); - - return paths; - } - - /** - * Creates a new <code>TreeModel</code> object. - * - * @param value the values stored in the model - */ - protected static TreeModel createTreeModel(Object value) - { - return new DefaultTreeModel(new DynamicUtilTreeNode(value, value)); - } - - /** - * Return the UI associated with this <code>JTree</code> object. - * - * @return the associated <code>TreeUI</code> object - */ - public TreeUI getUI() - { - return (TreeUI) ui; - } - - /** - * Sets the UI associated with this <code>JTree</code> object. - * - * @param ui the <code>TreeUI</code> to associate - */ - public void setUI(TreeUI ui) - { - super.setUI(ui); - } + private static final Object EXPANDED = new Object(); - /** - * This method resets the UI used to the Look and Feel defaults.. - */ - public void updateUI() - { - setUI((TreeUI) UIManager.getUI(this)); - revalidate(); - repaint(); - } - - /** - * This method returns the String ID of the UI class of Separator. - * - * @return The UI class' String ID. - */ - public String getUIClassID() - { - return "TreeUI"; - } - - /** - * Gets the AccessibleContext associated with this - * <code>JToggleButton</code>. - * - * @return the associated context - */ - public AccessibleContext getAccessibleContext() - { - return null; - } - - /** - * Returns the preferred viewport size. - * - * @return the preferred size - */ - public Dimension getPreferredScrollableViewportSize() - { - return new Dimension (getPreferredSize().width, getVisibleRowCount()*getRowHeight()); - } - - public int getScrollableUnitIncrement(Rectangle visibleRect, - int orientation, int direction) - { - return 1; - } - - public int getScrollableBlockIncrement(Rectangle visibleRect, - int orientation, int direction) - { - return 1; - } + private static final Object COLLAPSED = new Object(); - public boolean getScrollableTracksViewportWidth() + private boolean dragEnabled; + + private boolean expandsSelectedPaths; + + private TreePath anchorSelectionPath; + + private TreePath leadSelectionPath; + + /** + * This contains the state of all nodes in the tree. Al/ entries map the + * TreePath of a note to to its state. Valid states are EXPANDED and + * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED. + */ + private Hashtable nodeStates = new Hashtable(); + + protected transient TreeCellEditor cellEditor; + + protected transient TreeCellRenderer cellRenderer; + + protected boolean editable; + + protected boolean invokesStopCellEditing; + + protected boolean largeModel; + + protected boolean rootVisible; + + protected int rowHeight; + + protected boolean scrollsOnExpand; + + protected transient TreeSelectionModel selectionModel; + + protected boolean showsRootHandles; + + protected int toggleClickCount; + + protected transient TreeModel treeModel; + + protected int visibleRowCount; + + /** + * Handles TreeModelEvents to update the expandedState. + */ + protected transient TreeModelListener treeModelListener; + + /** + * Redirects TreeSelectionEvents so that the source is this JTree. + */ + protected TreeSelectionRedirector selectionRedirector = + new TreeSelectionRedirector(); + + /** + * Creates a new <code>JTree</code> object. + */ + public JTree() + { + this(createTreeModel(null)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param value the initial nodes in the tree + */ + public JTree(Hashtable value) + { + this(createTreeModel(value)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param value the initial nodes in the tree + */ + public JTree(Object[] value) + { + this(createTreeModel(value)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param model the model to use + */ + public JTree(TreeModel model) + { + updateUI(); + setRootVisible(true); + setModel(model); + setSelectionModel(new EmptySelectionModel()); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param root the root node + */ + public JTree(TreeNode root) + { + this(root, false); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param root the root node + * @param asksAllowChildren if false, all nodes without children are leaf + * nodes. If true, only nodes that do not allow children are leaf + * nodes. + */ + public JTree(TreeNode root, boolean asksAllowChildren) + { + this(new DefaultTreeModel(root, asksAllowChildren)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param value the initial nodes in the tree + */ + public JTree(Vector value) + { + this(createTreeModel(value)); + } + + public int getRowForPath(TreePath path) + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getRowForPath(this, path); + + return -1; + } + + public TreePath getPathForRow(int row) + { + TreeUI ui = getUI(); + return ui != null ? ui.getPathForRow(this, row) : null; + } + + protected TreePath[] getPathBetweenRows(int index0, int index1) + { + TreeUI ui = getUI(); + + if (ui == null) + return null; + + int minIndex = Math.min(index0, index1); + int maxIndex = Math.max(index0, index1); + TreePath[] paths = new TreePath[maxIndex - minIndex + 1]; + + for (int i = minIndex; i <= maxIndex; ++i) + paths[i - minIndex] = ui.getPathForRow(this, i); + + return paths; + } + + /** + * Creates a new <code>TreeModel</code> object. + * + * @param value the values stored in the model + */ + protected static TreeModel createTreeModel(Object value) + { + return new DefaultTreeModel(new DynamicUtilTreeNode(value, value)); + } + + /** + * Return the UI associated with this <code>JTree</code> object. + * + * @return the associated <code>TreeUI</code> object + */ + public TreeUI getUI() + { + return (TreeUI) ui; + } + + /** + * Sets the UI associated with this <code>JTree</code> object. + * + * @param ui the <code>TreeUI</code> to associate + */ + public void setUI(TreeUI ui) + { + super.setUI(ui); + } + + /** + * This method resets the UI used to the Look and Feel defaults.. + */ + public void updateUI() + { + setUI((TreeUI) UIManager.getUI(this)); + } + + /** + * This method returns the String ID of the UI class of Separator. + * + * @return The UI class' String ID. + */ + public String getUIClassID() + { + return "TreeUI"; + } + + /** + * Gets the AccessibleContext associated with this + * <code>JTree</code>. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + return new AccessibleJTree(); + } + + /** + * Returns the preferred viewport size. + * + * @return the preferred size + */ + public Dimension getPreferredScrollableViewportSize() + { + return new Dimension (getPreferredSize().width, getVisibleRowCount()*getRowHeight()); + } + + public int getScrollableUnitIncrement(Rectangle visibleRect, + int orientation, int direction) + { + return 1; + } + + public int getScrollableBlockIncrement(Rectangle visibleRect, + int orientation, int direction) + { + return 1; + } + + public boolean getScrollableTracksViewportHeight() { if (getParent() instanceof JViewport) return ((JViewport) getParent()).getHeight() > getPreferredSize().height; return false; } - - public boolean getScrollableTracksViewportHeight() + + public boolean getScrollableTracksViewportWidth() { if (getParent() instanceof JViewport) return ((JViewport) getParent()).getWidth() > getPreferredSize().width; return false; } - /** - * Adds a <code>TreeExpansionListener</code> object to the tree. - * - * @param listener the listener to add - */ - public void addTreeExpansionListener(TreeExpansionListener listener) - { - listenerList.add(TreeExpansionListener.class, listener); - } - - /** - * Removes a <code>TreeExpansionListener</code> object from the tree. - * - * @param listener the listener to remove - */ - public void removeTreeExpansionListener(TreeExpansionListener listener) - { - listenerList.remove(TreeExpansionListener.class, listener); - } - - /** - * Returns all added <code>TreeExpansionListener</code> objects. - * - * @return an array of listeners - */ - public TreeExpansionListener[] getTreeExpansionListeners() - { - return (TreeExpansionListener[]) getListeners(TreeExpansionListener.class); - } - - /** - * Notifies all listeners that the tree was collapsed. - * - * @param path the path to the node that was collapsed - */ - public void fireTreeCollapsed(TreePath path) - { - TreeExpansionEvent event = new TreeExpansionEvent(this, path); - TreeExpansionListener[] listeners = getTreeExpansionListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].treeCollapsed(event); - } - - /** - * Notifies all listeners that the tree was expanded. - * - * @param path the path to the node that was expanded - */ - public void fireTreeExpanded(TreePath path) - { - TreeExpansionEvent event = new TreeExpansionEvent(this, path); - TreeExpansionListener[] listeners = getTreeExpansionListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].treeExpanded(event); - } - - /** - * Adds a <code>TreeSelctionListener</code> object to the tree. - * - * @param listener the listener to add - */ - public void addTreeSelectionListener(TreeSelectionListener listener) - { - listenerList.add(TreeSelectionListener.class, listener); - } - - /** - * Removes a <code>TreeSelectionListener</code> object from the tree. - * - * @param listener the listener to remove - */ - public void removeTreeSelectionListener(TreeSelectionListener listener) - { - listenerList.remove(TreeSelectionListener.class, listener); - } - - /** - * Returns all added <code>TreeSelectionListener</code> objects. - * - * @return an array of listeners - */ - public TreeSelectionListener[] getTreeSelectionListeners() - { - return (TreeSelectionListener[]) - getListeners(TreeSelectionListener.class); - } - - /** - * Notifies all listeners when the selection of the tree changed. - * - * @param event the event to send - */ - protected void fireValueChanged(TreeSelectionEvent event) - { - TreeSelectionListener[] listeners = getTreeSelectionListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].valueChanged(event); - } - - /** - * Adds a <code>TreeWillExpandListener</code> object to the tree. - * - * @param listener the listener to add - */ - public void addTreeWillExpandListener(TreeWillExpandListener listener) - { - listenerList.add(TreeWillExpandListener.class, listener); - } - - /** - * Removes a <code>TreeWillExpandListener</code> object from the tree. - * - * @param listener the listener to remove - */ - public void removeTreeWillExpandListener(TreeWillExpandListener listener) - { - listenerList.remove(TreeWillExpandListener.class, listener); - } - - /** - * Returns all added <code>TreeWillExpandListener</code> objects. - * - * @return an array of listeners - */ - public TreeWillExpandListener[] getTreeWillExpandListeners() - { - return (TreeWillExpandListener[]) - getListeners(TreeWillExpandListener.class); - } - - /** - * Notifies all listeners that the tree will collapse. - * - * @param path the path to the node that will collapse - */ - public void fireTreeWillCollapse(TreePath path) throws ExpandVetoException - { - TreeExpansionEvent event = new TreeExpansionEvent(this, path); - TreeWillExpandListener[] listeners = getTreeWillExpandListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].treeWillCollapse(event); - } - - /** - * Notifies all listeners that the tree will expand. - * - * @param path the path to the node that will expand - */ - public void fireTreeWillExpand(TreePath path) throws ExpandVetoException - { - TreeExpansionEvent event = new TreeExpansionEvent(this, path); - TreeWillExpandListener[] listeners = getTreeWillExpandListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].treeWillExpand(event); - } - - /** - * Returns the model of this <code>JTree</code> object. - * - * @return the associated <code>TreeModel</code> - */ - public TreeModel getModel() - { - return treeModel; - } - - /** - * Sets the model to use in <code>JTree</code>. - * - * @param model the <code>TreeModel</code> to use - */ - public void setModel(TreeModel model) - { - if (treeModel == model) - return; - - // add treeModelListener to the new model - if (treeModelListener == null) - treeModelListener = createTreeModelListener(); - if (model != null) // as setModel(null) is allowed - model.addTreeModelListener(treeModelListener); - + /** + * Adds a <code>TreeExpansionListener</code> object to the tree. + * + * @param listener the listener to add + */ + public void addTreeExpansionListener(TreeExpansionListener listener) + { + listenerList.add(TreeExpansionListener.class, listener); + } + + /** + * Removes a <code>TreeExpansionListener</code> object from the tree. + * + * @param listener the listener to remove + */ + public void removeTreeExpansionListener(TreeExpansionListener listener) + { + listenerList.remove(TreeExpansionListener.class, listener); + } + + /** + * Returns all added <code>TreeExpansionListener</code> objects. + * + * @return an array of listeners + */ + public TreeExpansionListener[] getTreeExpansionListeners() + { + return (TreeExpansionListener[]) getListeners(TreeExpansionListener.class); + } + + /** + * Notifies all listeners that the tree was collapsed. + * + * @param path the path to the node that was collapsed + */ + public void fireTreeCollapsed(TreePath path) + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeExpansionListener[] listeners = getTreeExpansionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeCollapsed(event); + } + + /** + * Notifies all listeners that the tree was expanded. + * + * @param path the path to the node that was expanded + */ + public void fireTreeExpanded(TreePath path) + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeExpansionListener[] listeners = getTreeExpansionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeExpanded(event); + } + + /** + * Adds a <code>TreeSelctionListener</code> object to the tree. + * + * @param listener the listener to add + */ + public void addTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.add(TreeSelectionListener.class, listener); + } + + /** + * Removes a <code>TreeSelectionListener</code> object from the tree. + * + * @param listener the listener to remove + */ + public void removeTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.remove(TreeSelectionListener.class, listener); + } + + /** + * Returns all added <code>TreeSelectionListener</code> objects. + * + * @return an array of listeners + */ + public TreeSelectionListener[] getTreeSelectionListeners() + { + return (TreeSelectionListener[]) + getListeners(TreeSelectionListener.class); + } + + /** + * Notifies all listeners when the selection of the tree changed. + * + * @param event the event to send + */ + protected void fireValueChanged(TreeSelectionEvent event) + { + TreeSelectionListener[] listeners = getTreeSelectionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].valueChanged(event); + } + + /** + * Adds a <code>TreeWillExpandListener</code> object to the tree. + * + * @param listener the listener to add + */ + public void addTreeWillExpandListener(TreeWillExpandListener listener) + { + listenerList.add(TreeWillExpandListener.class, listener); + } + + /** + * Removes a <code>TreeWillExpandListener</code> object from the tree. + * + * @param listener the listener to remove + */ + public void removeTreeWillExpandListener(TreeWillExpandListener listener) + { + listenerList.remove(TreeWillExpandListener.class, listener); + } + + /** + * Returns all added <code>TreeWillExpandListener</code> objects. + * + * @return an array of listeners + */ + public TreeWillExpandListener[] getTreeWillExpandListeners() + { + return (TreeWillExpandListener[]) + getListeners(TreeWillExpandListener.class); + } + + /** + * Notifies all listeners that the tree will collapse. + * + * @param path the path to the node that will collapse + */ + public void fireTreeWillCollapse(TreePath path) throws ExpandVetoException + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeWillExpandListener[] listeners = getTreeWillExpandListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeWillCollapse(event); + } + + /** + * Notifies all listeners that the tree will expand. + * + * @param path the path to the node that will expand + */ + public void fireTreeWillExpand(TreePath path) throws ExpandVetoException + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeWillExpandListener[] listeners = getTreeWillExpandListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeWillExpand(event); + } + + /** + * Returns the model of this <code>JTree</code> object. + * + * @return the associated <code>TreeModel</code> + */ + public TreeModel getModel() + { + return treeModel; + } + + /** + * Sets the model to use in <code>JTree</code>. + * + * @param model the <code>TreeModel</code> to use + */ + public void setModel(TreeModel model) + { + if (treeModel == model) + return; + + // add treeModelListener to the new model + if (treeModelListener == null) + treeModelListener = createTreeModelListener(); + if (model != null) // as setModel(null) is allowed + model.addTreeModelListener(treeModelListener); + TreeModel oldValue = treeModel; treeModel = model; firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model); - } + updateUI(); + } - /** - * Checks if this <code>JTree</code> object is editable. - * - * @return <code>true</code> if this tree object is editable, - * <code>false</code> otherwise - */ - public boolean isEditable() - { - return editable; - } - - /** - * Sets the <code>editable</code> property. - * - * @param flag <code>true</code> to make this tree object editable, - * <code>false</code> otherwise - */ - public void setEditable(boolean flag) - { - if (editable == flag) - return; - - boolean oldValue = editable; - editable = flag; - firePropertyChange(EDITABLE_PROPERTY, oldValue, editable); - } - - /** - * Checks if the root element is visible. - * - * @return <code>true</code> if the root element is visible, - * <code>false</code> otherwise - */ - public boolean isRootVisible() - { - return rootVisible; - } - - public void setRootVisible(boolean flag) - { - if (rootVisible == flag) - return; - - boolean oldValue = rootVisible; - rootVisible = flag; - firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag); - } - - public boolean getShowsRootHandles() - { - return showsRootHandles; - } - - public void setShowsRootHandles(boolean flag) - { - if (showsRootHandles == flag) - return; - - boolean oldValue = showsRootHandles; - showsRootHandles = flag; - firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue, flag); - } - - public TreeCellEditor getCellEditor() - { - - return cellEditor; - } - - public void setCellEditor(TreeCellEditor editor) - { - if (cellEditor == editor) - return; - - TreeCellEditor oldValue = cellEditor; - cellEditor = editor; - firePropertyChange(CELL_EDITOR_PROPERTY, oldValue, editor); - } - - public TreeCellRenderer getCellRenderer() - { - return cellRenderer; - } - - public void setCellRenderer(TreeCellRenderer newRenderer) - { - if (cellRenderer == newRenderer) - return; - - TreeCellRenderer oldValue = cellRenderer; - cellRenderer = newRenderer; - firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, newRenderer); - } - - public TreeSelectionModel getSelectionModel() - { - return selectionModel; - } - - public void setSelectionModel(TreeSelectionModel model) - { - if (selectionModel == model) - return; - - if (selectionModel != null) - selectionModel.removeTreeSelectionListener(selectionRedirector); - - TreeSelectionModel oldValue = selectionModel; - selectionModel = model; - - if (selectionModel != null) - selectionModel.addTreeSelectionListener(selectionRedirector); - - firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model); - revalidate(); - repaint(); - } - - public int getVisibleRowCount() - { - return visibleRowCount; - } - - public void setVisibleRowCount(int rows) - { - if (visibleRowCount == rows) - return; - - int oldValue = visibleRowCount; - visibleRowCount = rows; - firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldValue, rows); - } - - public boolean isLargeModel() - { - return largeModel; - } - - public void setLargeModel(boolean large) - { - if (largeModel == large) - return; - - boolean oldValue = largeModel; - largeModel = large; - firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, large); - } - - public int getRowHeight() - { - - return rowHeight; - } - - public void setRowHeight(int height) - { - if (rowHeight == height) - return; - - int oldValue = rowHeight; - rowHeight = height; - firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, height); - } - - public boolean isFixedRowHeight() - { - return rowHeight > 0; - } - - public boolean getInvokesStopCellEditing() - { - return invokesStopCellEditing; - } - - public void setInvokesStopCellEditing(boolean invoke) - { - if (invokesStopCellEditing == invoke) - return; - - boolean oldValue = invokesStopCellEditing; - invokesStopCellEditing = invoke; - firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, - oldValue, invoke); - } - - /** - * @since 1.3 - */ - public int getToggleClickCount() - { - return toggleClickCount; - } + /** + * Checks if this <code>JTree</code> object is editable. + * + * @return <code>true</code> if this tree object is editable, + * <code>false</code> otherwise + */ + public boolean isEditable() + { + return editable; + } - /** - * @since 1.3 - */ - public void setToggleClickCount(int count) - { - if (toggleClickCount == count) - return; - - int oldValue = toggleClickCount; - toggleClickCount = count; - firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldValue, count); - } - - public void scrollPathToVisible(TreePath path) - { - if (path == null) - return; + /** + * Sets the <code>editable</code> property. + * + * @param flag <code>true</code> to make this tree object editable, + * <code>false</code> otherwise + */ + public void setEditable(boolean flag) + { + if (editable == flag) + return; - Rectangle rect = getPathBounds(path); - - if (rect == null) - return; - - scrollRectToVisible(rect); - } + boolean oldValue = editable; + editable = flag; + firePropertyChange(EDITABLE_PROPERTY, oldValue, editable); + } - public void scrollRowToVisible(int row) - { - scrollPathToVisible(getPathForRow(row)); - } - - public boolean getScrollsOnExpand() - { - return scrollsOnExpand; - } - - public void setScrollsOnExpand(boolean scroll) - { - if (scrollsOnExpand == scroll) - return; - - boolean oldValue = scrollsOnExpand; - scrollsOnExpand = scroll; - firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue, scroll); - } - - public void setSelectionPath(TreePath path) - { - selectionModel.setSelectionPath(path); - } - - public void setSelectionPaths(TreePath[] paths) - { - selectionModel.setSelectionPaths(paths); - } - - public void setSelectionRow(int row) - { - TreePath path = getPathForRow(row); - - if (path != null) - selectionModel.setSelectionPath(path); - } - - public void setSelectionRows(int[] rows) - { - // Make sure we have an UI so getPathForRow() does not return null. - if (rows == null || getUI() == null) - return; - - TreePath[] paths = new TreePath[rows.length]; - - for (int i = rows.length - 1; i >= 0; --i) - paths[i] = getPathForRow(rows[i]); - - setSelectionPaths(paths); - } - - public void setSelectionInterval(int index0, int index1) - { - TreePath[] paths = getPathBetweenRows(index0, index1); - - if (paths != null) - setSelectionPaths(paths); - } - - public void addSelectionPath(TreePath path) - { - selectionModel.addSelectionPath(path); - } - - public void addSelectionPaths(TreePath[] paths) - { - selectionModel.addSelectionPaths(paths); - } - - public void addSelectionRow(int row) - { - TreePath path = getPathForRow(row); - - if (path != null) - selectionModel.addSelectionPath(path); - } - - public void addSelectionRows(int[] rows) - { - // Make sure we have an UI so getPathForRow() does not return null. - if (rows == null || getUI() == null) - return; - - TreePath[] paths = new TreePath[rows.length]; + /** + * Checks if the root element is visible. + * + * @return <code>true</code> if the root element is visible, + * <code>false</code> otherwise + */ + public boolean isRootVisible() + { + return rootVisible; + } - for (int i = rows.length - 1; i >= 0; --i) - paths[i] = getPathForRow(rows[i]); - - addSelectionPaths(paths); - } + public void setRootVisible(boolean flag) + { + if (rootVisible == flag) + return; - public void addSelectionInterval(int index0, int index1) - { - TreePath[] paths = getPathBetweenRows(index0, index1); - - if (paths != null) - addSelectionPaths(paths); - } - - public void removeSelectionPath(TreePath path) - { - selectionModel.removeSelectionPath(path); - } - - public void removeSelectionPaths(TreePath[] paths) - { - selectionModel.removeSelectionPaths(paths); - } + boolean oldValue = rootVisible; + rootVisible = flag; + firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag); + } - public void removeSelectionRow(int row) - { - TreePath path = getPathForRow(row); + public boolean getShowsRootHandles() + { + return showsRootHandles; + } - if (path != null) - selectionModel.removeSelectionPath(path); - } + public void setShowsRootHandles(boolean flag) + { + if (showsRootHandles == flag) + return; + + boolean oldValue = showsRootHandles; + showsRootHandles = flag; + firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue, flag); + } - public void removeSelectionRows(int[] rows) - { - if (rows == null || getUI() == null) - return; + public TreeCellEditor getCellEditor() + { + return cellEditor; + } - TreePath[] paths = new TreePath[rows.length]; + public void setCellEditor(TreeCellEditor editor) + { + if (cellEditor == editor) + return; - for (int i = rows.length - 1; i >= 0; --i) - paths[i] = getPathForRow(rows[i]); + TreeCellEditor oldValue = cellEditor; + cellEditor = editor; + firePropertyChange(CELL_EDITOR_PROPERTY, oldValue, editor); + } - removeSelectionPaths(paths); - } + public TreeCellRenderer getCellRenderer() + { + return cellRenderer; + } - public void removeSelectionInterval(int index0, int index1) - { - TreePath[] paths = getPathBetweenRows(index0, index1); + public void setCellRenderer(TreeCellRenderer newRenderer) + { + if (cellRenderer == newRenderer) + return; - if (paths != null) - removeSelectionPaths(paths); - } + TreeCellRenderer oldValue = cellRenderer; + cellRenderer = newRenderer; + firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, newRenderer); + } - public void clearSelection() - { - selectionModel.clearSelection(); - setLeadSelectionPath(null); - } + public TreeSelectionModel getSelectionModel() + { + return selectionModel; + } - public TreePath getLeadSelectionPath() - { - return leadSelectionPath; - } + public void setSelectionModel(TreeSelectionModel model) + { + if (selectionModel == model) + return; - /** - * @since 1.3 - */ - public void setLeadSelectionPath(TreePath path) - { - if (leadSelectionPath == path) - return; - - TreePath oldValue = leadSelectionPath; - leadSelectionPath = path; - firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path); - } - - /** - * @since 1.3 - */ - public TreePath getAnchorSelectionPath() - { - return anchorSelectionPath; - } + if (selectionModel != null) + selectionModel.removeTreeSelectionListener(selectionRedirector); - /** - * @since 1.3 - */ - public void setAnchorSelectionPath(TreePath path) - { - if (anchorSelectionPath == path) - return; - - TreePath oldValue = anchorSelectionPath; - anchorSelectionPath = path; - firePropertyChange(ANCHOR_SELECTION_PATH_PROPERTY, oldValue, path); - } - - public int getLeadSelectionRow() - { - return selectionModel.getLeadSelectionRow(); - } - - public int getMaxSelectionRow() - { - return selectionModel.getMaxSelectionRow(); - } - - public int getMinSelectionRow() - { - return selectionModel.getMinSelectionRow(); - } - - public int getSelectionCount() - { - return selectionModel.getSelectionCount(); - } - - public TreePath getSelectionPath() - { - return selectionModel.getSelectionPath(); - } - - public TreePath[] getSelectionPaths() - { - return selectionModel.getSelectionPaths(); - } - - public int[] getSelectionRows() - { - return selectionModel.getSelectionRows(); - } - - public boolean isPathSelected(TreePath path) - { - return selectionModel.isPathSelected(path); - } - - public boolean isRowSelected(int row) - { - return selectionModel.isPathSelected(getPathForRow(row)); - } - - public boolean isSelectionEmpty() - { - return selectionModel.isSelectionEmpty(); - } - - /** - * Return the value of the <code>dragEnabled</code> property. - * - * @return the value - * - * @since 1.4 - */ - public boolean getDragEnabled() - { - return dragEnabled; - } - - /** - * Set the <code>dragEnabled</code> property. - * - * @param enabled new value - * - * @since 1.4 - */ - public void setDragEnabled(boolean enabled) - { + TreeSelectionModel oldValue = selectionModel; + selectionModel = model; - dragEnabled = enabled; - } + if (selectionModel != null) + selectionModel.addTreeSelectionListener(selectionRedirector); - public int getRowCount() - { - TreeUI ui = getUI(); + firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model); + revalidate(); + repaint(); + } - if (ui != null) - return ui.getRowCount(this); + public int getVisibleRowCount() + { + return visibleRowCount; + } - return 0; - } + public void setVisibleRowCount(int rows) + { + if (visibleRowCount == rows) + return; - public void collapsePath(TreePath path) - { - try - { - fireTreeWillCollapse(path); - } - catch (ExpandVetoException ev) - { - } - setExpandedState(path, false); - fireTreeCollapsed(path); - } + int oldValue = visibleRowCount; + visibleRowCount = rows; + firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldValue, rows); + } - public void collapseRow(int row) - { - if (row < 0 || row >= getRowCount()) - return; + public boolean isLargeModel() + { + return largeModel; + } - TreePath path = getPathForRow(row); + public void setLargeModel(boolean large) + { + if (largeModel == large) + return; - if (path != null) - collapsePath(path); - } + boolean oldValue = largeModel; + largeModel = large; + firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, large); + } - public void expandPath(TreePath path) - { - // Don't expand if last path component is a leaf node. - if ((path == null) || (treeModel.isLeaf(path.getLastPathComponent()))) - return; - - try - { - fireTreeWillExpand(path); - } - catch (ExpandVetoException ev) - { - } - - setExpandedState(path, true); - fireTreeExpanded(path); - } + public int getRowHeight() + { + return rowHeight; + } - public void expandRow(int row) - { - if (row < 0 || row >= getRowCount()) - return; + public void setRowHeight(int height) + { + if (rowHeight == height) + return; - TreePath path = getPathForRow(row); + int oldValue = rowHeight; + rowHeight = height; + firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, height); + } - if (path != null) - expandPath(path); - } + public boolean isFixedRowHeight() + { + return rowHeight > 0; + } - public boolean isCollapsed(TreePath path) - { - return !isExpanded(path); - } + public boolean getInvokesStopCellEditing() + { + return invokesStopCellEditing; + } - public boolean isCollapsed(int row) - { - if (row < 0 || row >= getRowCount()) - return false; + public void setInvokesStopCellEditing(boolean invoke) + { + if (invokesStopCellEditing == invoke) + return; - TreePath path = getPathForRow(row); + boolean oldValue = invokesStopCellEditing; + invokesStopCellEditing = invoke; + firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, + oldValue, invoke); + } - if (path != null) - return isCollapsed(path); + /** + * @since 1.3 + */ + public int getToggleClickCount() + { + return toggleClickCount; + } - return false; - } + /** + * @since 1.3 + */ + public void setToggleClickCount(int count) + { + if (toggleClickCount == count) + return; - public boolean isExpanded(TreePath path) - { - if (path == null) - return false; + int oldValue = toggleClickCount; + toggleClickCount = count; + firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldValue, count); + } - Object state = nodeStates.get(path); + public void scrollPathToVisible(TreePath path) + { + if (path == null) + return; + + Object[] oPath = path.getPath(); + TreePath temp = new TreePath(oPath[0]); + boolean stop = false; + int i = 1; + while (!stop) + { + while (isVisible(temp)) + if (i < oPath.length) + temp = temp.pathByAddingChild(oPath[i++]); + else + { + stop = true; + break; + } + makeVisible(temp); + } + Rectangle rect = getPathBounds(path); + scrollRectToVisible(rect); + revalidate(); + repaint(); + } - if ((state == null) || (state != EXPANDED)) - return false; + public void scrollRowToVisible(int row) + { + scrollPathToVisible(getPathForRow(row)); + } - TreePath parent = path.getParentPath(); + public boolean getScrollsOnExpand() + { + return scrollsOnExpand; + } - if (parent != null) - return isExpanded(parent); + public void setScrollsOnExpand(boolean scroll) + { + if (scrollsOnExpand == scroll) + return; - return true; - } + boolean oldValue = scrollsOnExpand; + scrollsOnExpand = scroll; + firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue, scroll); + } - public boolean isExpanded(int row) - { - if (row < 0 || row >= getRowCount()) - return false; + public void setSelectionPath(TreePath path) + { + selectionModel.setSelectionPath(path); + } - TreePath path = getPathForRow(row); + public void setSelectionPaths(TreePath[] paths) + { + selectionModel.setSelectionPaths(paths); + } - if (path != null) - return isExpanded(path); + public void setSelectionRow(int row) + { + TreePath path = getPathForRow(row); - return false; - } + if (path != null) + selectionModel.setSelectionPath(path); + } - /** - * @since 1.3 - */ - public boolean getExpandsSelectedPaths() - { - return expandsSelectedPaths; - } + public void setSelectionRows(int[] rows) + { + // Make sure we have an UI so getPathForRow() does not return null. + if (rows == null || getUI() == null) + return; - /** - * @since 1.3 - */ - public void setExpandsSelectedPaths(boolean flag) - { - if (expandsSelectedPaths == flag) - return; + TreePath[] paths = new TreePath[rows.length]; - boolean oldValue = expandsSelectedPaths; - expandsSelectedPaths = flag; - firePropertyChange(EXPANDS_SELECTED_PATHS_PROPERTY, oldValue, flag); - } + for (int i = rows.length - 1; i >= 0; --i) + paths[i] = getPathForRow(rows[i]); - public Rectangle getPathBounds(TreePath path) - { - TreeUI ui = getUI(); + setSelectionPaths(paths); + } - if (ui == null) - return null; + public void setSelectionInterval(int index0, int index1) + { + TreePath[] paths = getPathBetweenRows(index0, index1); - return ui.getPathBounds(this, path); - } + if (paths != null) + setSelectionPaths(paths); + } - public Rectangle getRowBounds(int row) - { - TreePath path = getPathForRow(row); + public void addSelectionPath(TreePath path) + { + selectionModel.addSelectionPath(path); + } - if (path != null) - return getPathBounds(path); + public void addSelectionPaths(TreePath[] paths) + { + selectionModel.addSelectionPaths(paths); + } - return null; - } + public void addSelectionRow(int row) + { + TreePath path = getPathForRow(row); - public boolean isEditing() - { - TreeUI ui = getUI(); + if (path != null) + selectionModel.addSelectionPath(path); + } - if (ui != null) - return ui.isEditing(this); + public void addSelectionRows(int[] rows) + { + // Make sure we have an UI so getPathForRow() does not return null. + if (rows == null || getUI() == null) + return; - return false; - } + TreePath[] paths = new TreePath[rows.length]; - public boolean stopEditing() - { - TreeUI ui = getUI(); + for (int i = rows.length - 1; i >= 0; --i) + paths[i] = getPathForRow(rows[i]); - if (ui != null) - return ui.stopEditing(this); + addSelectionPaths(paths); + } - return false; - } + public void addSelectionInterval(int index0, int index1) + { + TreePath[] paths = getPathBetweenRows(index0, index1); - public void cancelEditing() - { - TreeUI ui = getUI(); + if (paths != null) + addSelectionPaths(paths); + } - if (ui != null) - ui.cancelEditing(this); - } + public void removeSelectionPath(TreePath path) + { + selectionModel.removeSelectionPath(path); + } - public void startEditingAtPath(TreePath path) - { - TreeUI ui = getUI(); + public void removeSelectionPaths(TreePath[] paths) + { + selectionModel.removeSelectionPaths(paths); + } - if (ui != null) - ui.startEditingAtPath(this, path); - } + public void removeSelectionRow(int row) + { + TreePath path = getPathForRow(row); - public TreePath getEditingPath() - { - TreeUI ui = getUI(); + if (path != null) + selectionModel.removeSelectionPath(path); + } - if (ui != null) - return ui.getEditingPath(this); + public void removeSelectionRows(int[] rows) + { + if (rows == null || getUI() == null) + return; - return null; - } + TreePath[] paths = new TreePath[rows.length]; - public TreePath getPathForLocation(int x, int y) - { - TreePath path = getClosestPathForLocation(x, y); + for (int i = rows.length - 1; i >= 0; --i) + paths[i] = getPathForRow(rows[i]); - if (path != null) - { - Rectangle rect = getPathBounds(path); + removeSelectionPaths(paths); + } - if ((rect != null) && rect.contains(x, y)) - return path; - } + public void removeSelectionInterval(int index0, int index1) + { + TreePath[] paths = getPathBetweenRows(index0, index1); - return null; - } + if (paths != null) + removeSelectionPaths(paths); + } - public int getRowForLocation(int x, int y) - { - TreePath path = getPathForLocation(x, y); + public void clearSelection() + { + selectionModel.clearSelection(); + setLeadSelectionPath(null); + } - if (path != null) - return getRowForPath(path); + public TreePath getLeadSelectionPath() + { + return leadSelectionPath; + } - return -1; - } + /** + * @since 1.3 + */ + public void setLeadSelectionPath(TreePath path) + { + if (leadSelectionPath == path) + return; + + TreePath oldValue = leadSelectionPath; + leadSelectionPath = path; + firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path); + } - public TreePath getClosestPathForLocation(int x, int y) - { - TreeUI ui = getUI(); + /** + * @since 1.3 + */ + public TreePath getAnchorSelectionPath() + { + return anchorSelectionPath; + } - if (ui != null) - return ui.getClosestPathForLocation(this, x, y); + /** + * @since 1.3 + */ + public void setAnchorSelectionPath(TreePath path) + { + if (anchorSelectionPath == path) + return; - return null; - } + TreePath oldValue = anchorSelectionPath; + anchorSelectionPath = path; + firePropertyChange(ANCHOR_SELECTION_PATH_PROPERTY, oldValue, path); + } - public int getClosestRowForLocation(int x, int y) - { - TreePath path = getClosestPathForLocation(x, y); + public int getLeadSelectionRow() + { + return selectionModel.getLeadSelectionRow(); + } - if (path != null) - return getRowForPath(path); + public int getMaxSelectionRow() + { + return selectionModel.getMaxSelectionRow(); + } - return -1; - } + public int getMinSelectionRow() + { + return selectionModel.getMinSelectionRow(); + } - public Object getLastSelectedPathComponent() - { - TreePath path = getSelectionPath(); + public int getSelectionCount() + { + return selectionModel.getSelectionCount(); + } - if (path != null) - return path.getLastPathComponent(); + public TreePath getSelectionPath() + { + return selectionModel.getSelectionPath(); + } - return null; - } + public TreePath[] getSelectionPaths() + { + return selectionModel.getSelectionPaths(); + } - private void doExpandParents(TreePath path, boolean state) - { - TreePath parent = path.getParentPath(); - - if (!isExpanded(parent) && parent != null) - doExpandParents(parent, false); + public int[] getSelectionRows() + { + return selectionModel.getSelectionRows(); + } - nodeStates.put(path, state ? EXPANDED : COLLAPSED); - } + public boolean isPathSelected(TreePath path) + { + return selectionModel.isPathSelected(path); + } - protected void setExpandedState(TreePath path, boolean state) - { - if (path == null) - return; - TreePath parent = path.getParentPath(); + public boolean isRowSelected(int row) + { + return selectionModel.isPathSelected(getPathForRow(row)); + } - doExpandParents(path, state); - } + public boolean isSelectionEmpty() + { + return selectionModel.isSelectionEmpty(); + } - protected void clearToggledPaths() - { - nodeStates.clear(); - } + /** + * Return the value of the <code>dragEnabled</code> property. + * + * @return the value + * + * @since 1.4 + */ + public boolean getDragEnabled() + { + return dragEnabled; + } - protected Enumeration getDescendantToggledPaths(TreePath parent) - { - if (parent == null) - return null; + /** + * Set the <code>dragEnabled</code> property. + * + * @param enabled new value + * + * @since 1.4 + */ + public void setDragEnabled(boolean enabled) + { + dragEnabled = enabled; + } - Enumeration nodes = nodeStates.keys(); - Vector result = new Vector(); + public int getRowCount() + { + TreeUI ui = getUI(); - while (nodes.hasMoreElements()) - { - TreePath path = (TreePath) nodes.nextElement(); + if (ui != null) + return ui.getRowCount(this); - if (path.isDescendant(parent)) - result.addElement(path); - } + return 0; + } - return result.elements(); - } + public void collapsePath(TreePath path) + { + try + { + fireTreeWillCollapse(path); + } + catch (ExpandVetoException ev) + { + // We do nothing if attempt has been vetoed. + } + setExpandedState(path, false); + fireTreeCollapsed(path); + } - public boolean hasBeenExpanded(TreePath path) - { - if (path == null) - return false; + public void collapseRow(int row) + { + if (row < 0 || row >= getRowCount()) + return; - return nodeStates.get(path) != null; - } + TreePath path = getPathForRow(row); - public boolean isVisible(TreePath path) - { - if (path == null) - return false; + if (path != null) + collapsePath(path); + } - TreePath parent = path.getParentPath(); + public void expandPath(TreePath path) + { + // Don't expand if path is null + if (path == null) + return; + + try + { + fireTreeWillExpand(path); + } + catch (ExpandVetoException ev) + { + // We do nothing if attempt has been vetoed. + } + + setExpandedState(path, true); + fireTreeExpanded(path); + } - if (parent == null) - return true; // Is root node. + public void expandRow(int row) + { + if (row < 0 || row >= getRowCount()) + return; - return isExpanded(parent); - } + TreePath path = getPathForRow(row); - public void makeVisible(TreePath path) - { - if (path == null) - return; + if (path != null) + expandPath(path); + } - expandPath(path.getParentPath()); - } + public boolean isCollapsed(TreePath path) + { + return !isExpanded(path); + } - public boolean isPathEditable(TreePath path) - { - return isEditable(); - } + public boolean isCollapsed(int row) + { + if (row < 0 || row >= getRowCount()) + return false; - /** - * Creates and returns an instance of {@link TreeModelHandler}. - * - * @returns an instance of {@link TreeModelHandler} - */ - protected TreeModelListener createTreeModelListener() - { - return new TreeModelHandler(); - } - - /** - * Returns a sample TreeModel that can be used in a JTree. This can be used - * in Bean- or GUI-Builders to show something interesting. - * - * @return a sample TreeModel that can be used in a JTree - */ - protected static TreeModel getDefaultTreeModel() - { - DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root node"); - DefaultMutableTreeNode child1 = new DefaultMutableTreeNode( - "Child node 1"); - DefaultMutableTreeNode child11 = new DefaultMutableTreeNode( - "Child node 1.1"); - DefaultMutableTreeNode child12 = new DefaultMutableTreeNode( - "Child node 1.2"); - DefaultMutableTreeNode child13 = new DefaultMutableTreeNode( - "Child node 1.3"); - DefaultMutableTreeNode child2 = new DefaultMutableTreeNode( - "Child node 2"); - DefaultMutableTreeNode child21 = new DefaultMutableTreeNode( - "Child node 2.1"); - DefaultMutableTreeNode child22 = new DefaultMutableTreeNode( - "Child node 2.2"); - DefaultMutableTreeNode child23 = new DefaultMutableTreeNode( - "Child node 2.3"); - DefaultMutableTreeNode child24 = new DefaultMutableTreeNode( - "Child node 2.4"); - - DefaultMutableTreeNode child3 = new DefaultMutableTreeNode( - "Child node 3"); - root.add(child1); - root.add(child2); - root.add(child3); - child1.add(child11); - child1.add(child12); - child1.add(child13); - child2.add(child21); - child2.add(child22); - child2.add(child23); - child2.add(child24); - return new DefaultTreeModel(root); - } - - /** - * Converts the specified value to a String. This is used by the renderers - * of this JTree and its nodes. - * - * This implementation simply returns <code>value.toString()</code> and - * ignores all other parameters. Subclass this method to control the - * conversion. - * - * @param value the value that is converted to a String - * @param selected indicates if that value is selected or not - * @param expanded indicates if that value is expanded or not - * @param leaf indicates if that value is a leaf node or not - * @param row the row of the node - * @param hasFocus indicates if that node has focus or not - */ - public String convertValueToText(Object value, boolean selected, - boolean expanded, boolean leaf, int row, boolean hasFocus) - { - return value.toString(); - } - - /** - * A String representation of this JTree. This is intended to be used for - * debugging. The returned string may be empty but may not be - * <code>null</code>. - * - * @return a String representation of this JTree - */ - public String paramString() - { - // TODO: this is completely legal, but it would possibly be nice - // to return some more content, like the tree structure, some properties - // etc ... - return ""; - } - - /** - * Returns all TreePath objects which are a descendants of the given path - * and are exapanded at the moment of the execution of this method. If the - * state of any node is beeing toggled while this method is executing this - * change may be left unaccounted. - * - * @param path The parent of this request - * @return An Enumeration containing TreePath objects - */ - public Enumeration getExpandedDescendants(TreePath path) - { - Enumeration paths = nodeStates.keys(); - Vector relevantPaths = new Vector(); - while (paths.hasMoreElements()) - { - TreePath nextPath = (TreePath) paths.nextElement(); - if (nodeStates.get(nextPath) == EXPANDED - && path.isDescendant(nextPath)) - { - relevantPaths.add(nextPath); - } - } - return relevantPaths.elements(); - } - - /** - * Returns the next table element (beginning from the row - * <code>startingRow</code> that starts with <code>prefix</code>. - * Searching is done in the direction specified by <code>bias</code>. - * - * @param prefix the prefix to search for in the cell values - * @param startingRow the index of the row where to start searching from - * @param bias the search direction, either {@link Position.Bias#Forward} or - * {@link Position.Bias#Backward} - * - * @return the path to the found element or -1 if no such element has been - * found - * - * @throws IllegalArgumentException if prefix is <code>null</code> or - * startingRow is not valid - * - * @since 1.4 - */ - public TreePath getNextMatch(String prefix, int startingRow, - Position.Bias bias) - { - if (prefix == null) - throw new IllegalArgumentException( - "The argument 'prefix' must not be" + " null."); - if (startingRow < 0) - throw new IllegalArgumentException( - "The argument 'startingRow' must not" - + " be less than zero."); - - int size = getRowCount(); - if (startingRow > size) - throw new IllegalArgumentException( - "The argument 'startingRow' must not" - + " be greater than the number of" - + " elements in the TreeModel."); - - TreePath foundPath = null; - if (bias == Position.Bias.Forward) - { - for (int i = startingRow; i < size; i++) - { - TreePath path = getPathForRow(i); - Object o = path.getLastPathComponent(); - // FIXME: in the following call to convertValueToText the - // last argument (hasFocus) should be done right. - String item = convertValueToText(o, isRowSelected(i), - isExpanded(i), treeModel.isLeaf(o), i, false); - if (item.startsWith(prefix)) - { - foundPath = path; - break; - } - } - } else - { - for (int i = startingRow; i >= 0; i--) - { - TreePath path = getPathForRow(i); - Object o = path.getLastPathComponent(); - // FIXME: in the following call to convertValueToText the - // last argument (hasFocus) should be done right. - String item = convertValueToText(o, isRowSelected(i), - isExpanded(i), treeModel.isLeaf(o), i, false); - if (item.startsWith(prefix)) - { - foundPath = path; - break; - } - } - } - return foundPath; - } - - /** - * Removes any paths in the current set of selected paths that are - * descendants of <code>path</code>. If <code>includePath</code> is set - * to <code>true</code> and <code>path</code> itself is selected, then - * it will be removed too. - * - * @param path the path from which selected descendants are to be removed - * @param includeSelected if <code>true</code> then <code>path</code> itself - * will also be remove if it's selected - * - * @return <code>true</code> if something has been removed, - * <code>false</code> otherwise - * - * @since 1.3 - */ - protected boolean removeDescendantSelectedPaths(TreePath path, - boolean includeSelected) - { - boolean removedSomething = false; - TreePath[] selected = getSelectionPaths(); - for (int index = 0; index < selected.length; index++) - { - if ((selected[index] == path && includeSelected) - || (selected[index].isDescendant(path))) - { - removeSelectionPath(selected[index]); - removedSomething = true; - } - } - return removedSomething; - } + TreePath path = getPathForRow(row); + + if (path != null) + return isCollapsed(path); + + return false; + } + + public boolean isExpanded(TreePath path) + { + if (path == null) + return false; + + Object state = nodeStates.get(path); + + if ((state == null) || (state != EXPANDED)) + return false; + + TreePath parent = path.getParentPath(); + + if (parent != null) + return isExpanded(parent); + + return true; + } + + public boolean isExpanded(int row) + { + if (row < 0 || row >= getRowCount()) + return false; + + TreePath path = getPathForRow(row); + + if (path != null) + return isExpanded(path); + + return false; + } + + /** + * @since 1.3 + */ + public boolean getExpandsSelectedPaths() + { + return expandsSelectedPaths; + } + + /** + * @since 1.3 + */ + public void setExpandsSelectedPaths(boolean flag) + { + if (expandsSelectedPaths == flag) + return; + + boolean oldValue = expandsSelectedPaths; + expandsSelectedPaths = flag; + firePropertyChange(EXPANDS_SELECTED_PATHS_PROPERTY, oldValue, flag); + } + + public Rectangle getPathBounds(TreePath path) + { + TreeUI ui = getUI(); + + if (ui == null) + return null; + + return ui.getPathBounds(this, path); + } + + public Rectangle getRowBounds(int row) + { + TreePath path = getPathForRow(row); + + if (path != null) + return getPathBounds(path); + + return null; + } + + public boolean isEditing() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.isEditing(this); + + return false; + } + + public boolean stopEditing() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.stopEditing(this); + + return false; + } + + public void cancelEditing() + { + TreeUI ui = getUI(); + + if (ui != null) + ui.cancelEditing(this); + } + + public void startEditingAtPath(TreePath path) + { + TreeUI ui = getUI(); + + if (ui != null) + ui.startEditingAtPath(this, path); + } + + public TreePath getEditingPath() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getEditingPath(this); + + return null; + } + + public TreePath getPathForLocation(int x, int y) + { + TreePath path = getClosestPathForLocation(x, y); + + if (path != null) + { + Rectangle rect = getPathBounds(path); + + if ((rect != null) && rect.contains(x, y)) + return path; + } + + return null; + } + + public int getRowForLocation(int x, int y) + { + TreePath path = getPathForLocation(x, y); + + if (path != null) + return getRowForPath(path); + + return -1; + } + + public TreePath getClosestPathForLocation(int x, int y) + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getClosestPathForLocation(this, x, y); + + return null; + } + + public int getClosestRowForLocation(int x, int y) + { + TreePath path = getClosestPathForLocation(x, y); + + if (path != null) + return getRowForPath(path); + + return -1; + } + + public Object getLastSelectedPathComponent() + { + TreePath path = getSelectionPath(); + + if (path != null) + return path.getLastPathComponent(); + + return null; + } + + private void doExpandParents(TreePath path, boolean state) + { + TreePath parent = path.getParentPath(); + + if (!isExpanded(parent) && parent != null) + doExpandParents(parent, false); + + nodeStates.put(path, state ? EXPANDED : COLLAPSED); + } + + protected void setExpandedState(TreePath path, boolean state) + { + if (path == null) + return; + + doExpandParents(path, state); + } + + protected void clearToggledPaths() + { + nodeStates.clear(); + } + + protected Enumeration getDescendantToggledPaths(TreePath parent) + { + if (parent == null) + return null; + + Enumeration nodes = nodeStates.keys(); + Vector result = new Vector(); + + while (nodes.hasMoreElements()) + { + TreePath path = (TreePath) nodes.nextElement(); + + if (path.isDescendant(parent)) + result.addElement(path); + } + + return result.elements(); + } + + public boolean hasBeenExpanded(TreePath path) + { + if (path == null) + return false; + + return nodeStates.get(path) != null; + } + + public boolean isVisible(TreePath path) + { + if (path == null) + return false; + + TreePath parent = path.getParentPath(); + + if (parent == null) + return true; // Is root node. + + return isExpanded(parent); + } + + public void makeVisible(TreePath path) + { + if (path == null) + return; + + expandPath(path.getParentPath()); + } + + public boolean isPathEditable(TreePath path) + { + return isEditable(); + } + + /** + * Creates and returns an instance of {@link TreeModelHandler}. + * + * @return an instance of {@link TreeModelHandler} + */ + protected TreeModelListener createTreeModelListener() + { + return new TreeModelHandler(); + } + + /** + * Returns a sample TreeModel that can be used in a JTree. This can be used + * in Bean- or GUI-Builders to show something interesting. + * + * @return a sample TreeModel that can be used in a JTree + */ + protected static TreeModel getDefaultTreeModel() + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root node"); + DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Child node 1"); + DefaultMutableTreeNode child11 = + new DefaultMutableTreeNode("Child node 1.1"); + DefaultMutableTreeNode child12 = + new DefaultMutableTreeNode("Child node 1.2"); + DefaultMutableTreeNode child13 = + new DefaultMutableTreeNode("Child node 1.3"); + DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Child node 2"); + DefaultMutableTreeNode child21 = + new DefaultMutableTreeNode("Child node 2.1"); + DefaultMutableTreeNode child22 = + new DefaultMutableTreeNode("Child node 2.2"); + DefaultMutableTreeNode child23 = + new DefaultMutableTreeNode("Child node 2.3"); + DefaultMutableTreeNode child24 = + new DefaultMutableTreeNode("Child node 2.4"); + + DefaultMutableTreeNode child3 = new DefaultMutableTreeNode("Child node 3"); + root.add(child1); + root.add(child2); + root.add(child3); + child1.add(child11); + child1.add(child12); + child1.add(child13); + child2.add(child21); + child2.add(child22); + child2.add(child23); + child2.add(child24); + return new DefaultTreeModel(root); + } + + /** + * Converts the specified value to a String. This is used by the renderers + * of this JTree and its nodes. + * + * This implementation simply returns <code>value.toString()</code> and + * ignores all other parameters. Subclass this method to control the + * conversion. + * + * @param value the value that is converted to a String + * @param selected indicates if that value is selected or not + * @param expanded indicates if that value is expanded or not + * @param leaf indicates if that value is a leaf node or not + * @param row the row of the node + * @param hasFocus indicates if that node has focus or not + */ + public String convertValueToText(Object value, boolean selected, + boolean expanded, boolean leaf, int row, boolean hasFocus) + { + return value.toString(); + } + + /** + * A String representation of this JTree. This is intended to be used for + * debugging. The returned string may be empty but may not be + * <code>null</code>. + * + * @return a String representation of this JTree + */ + public String paramString() + { + // TODO: this is completely legal, but it would possibly be nice + // to return some more content, like the tree structure, some properties + // etc ... + return ""; + } + + /** + * Returns all TreePath objects which are a descendants of the given path + * and are exapanded at the moment of the execution of this method. If the + * state of any node is beeing toggled while this method is executing this + * change may be left unaccounted. + * + * @param path The parent of this request + * + * @return An Enumeration containing TreePath objects + */ + public Enumeration getExpandedDescendants(TreePath path) + { + Enumeration paths = nodeStates.keys(); + Vector relevantPaths = new Vector(); + while (paths.hasMoreElements()) + { + TreePath nextPath = (TreePath) paths.nextElement(); + if (nodeStates.get(nextPath) == EXPANDED + && path.isDescendant(nextPath)) + { + relevantPaths.add(nextPath); + } + } + return relevantPaths.elements(); + } + + /** + * Returns the next table element (beginning from the row + * <code>startingRow</code> that starts with <code>prefix</code>. + * Searching is done in the direction specified by <code>bias</code>. + * + * @param prefix the prefix to search for in the cell values + * @param startingRow the index of the row where to start searching from + * @param bias the search direction, either {@link Position.Bias#Forward} or + * {@link Position.Bias#Backward} + * + * @return the path to the found element or -1 if no such element has been + * found + * + * @throws IllegalArgumentException if prefix is <code>null</code> or + * startingRow is not valid + * + * @since 1.4 + */ + public TreePath getNextMatch(String prefix, int startingRow, + Position.Bias bias) + { + if (prefix == null) + throw new IllegalArgumentException("The argument 'prefix' must not be" + + " null."); + if (startingRow < 0) + throw new IllegalArgumentException("The argument 'startingRow' must not" + + " be less than zero."); + + int size = getRowCount(); + if (startingRow > size) + throw new IllegalArgumentException("The argument 'startingRow' must not" + + " be greater than the number of" + + " elements in the TreeModel."); + + TreePath foundPath = null; + if (bias == Position.Bias.Forward) + { + for (int i = startingRow; i < size; i++) + { + TreePath path = getPathForRow(i); + Object o = path.getLastPathComponent(); + // FIXME: in the following call to convertValueToText the + // last argument (hasFocus) should be done right. + String item = convertValueToText(o, isRowSelected(i), + isExpanded(i), treeModel.isLeaf(o), + i, false); + if (item.startsWith(prefix)) + { + foundPath = path; + break; + } + } + } + else + { + for (int i = startingRow; i >= 0; i--) + { + TreePath path = getPathForRow(i); + Object o = path.getLastPathComponent(); + // FIXME: in the following call to convertValueToText the + // last argument (hasFocus) should be done right. + String item = convertValueToText(o, isRowSelected(i), + isExpanded(i), treeModel.isLeaf(o), i, false); + if (item.startsWith(prefix)) + { + foundPath = path; + break; + } + } + } + return foundPath; + } + + /** + * Removes any paths in the current set of selected paths that are + * descendants of <code>path</code>. If <code>includePath</code> is set + * to <code>true</code> and <code>path</code> itself is selected, then + * it will be removed too. + * + * @param path the path from which selected descendants are to be removed + * @param includeSelected if <code>true</code> then <code>path</code> itself + * will also be remove if it's selected + * + * @return <code>true</code> if something has been removed, + * <code>false</code> otherwise + * + * @since 1.3 + */ + protected boolean removeDescendantSelectedPaths(TreePath path, + boolean includeSelected) + { + boolean removedSomething = false; + TreePath[] selected = getSelectionPaths(); + for (int index = 0; index < selected.length; index++) + { + if ((selected[index] == path && includeSelected) + || (selected[index].isDescendant(path))) + { + removeSelectionPath(selected[index]); + removedSomething = true; + } + } + return removedSomething; + } + + /** + * Removes any descendants of the TreePaths in toRemove that have been + * expanded. + * + * @param toRemove - Enumeration of TreePaths that need to be removed from + * cache of toggled tree paths. + */ + protected void removeDescendantToggledPaths(Enumeration toRemove) + { + while (toRemove.hasMoreElements()) + { + TreePath current = (TreePath) toRemove.nextElement(); + Enumeration descendants = getDescendantToggledPaths(current); + + while (descendants.hasMoreElements()) + { + TreePath currentDes = (TreePath) descendants.nextElement(); + if (isExpanded(currentDes)) + nodeStates.remove(currentDes); + } + } + } + + /** + * Sent when the tree has changed enough that we need to resize the bounds, + * but not enough that we need to remove the expanded node set (e.g nodes + * were expanded or collapsed, or nodes were inserted into the tree). You + * should never have to invoke this, the UI will invoke this as it needs to. + */ + public void treeDidChange() + { + repaint(); + } } |