home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / swing / JTree.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  127.3 KB  |  3,509 lines

  1. /*
  2.  * @(#)JTree.java    1.70 98/02/12
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package java.awt.swing;
  22.  
  23. import java.awt.*;
  24. import java.awt.event.*;
  25. import java.beans.*;
  26. import java.io.*;
  27. import java.util.*;
  28. import java.awt.swing.event.*;
  29. import java.awt.swing.plaf.TreeUI;
  30. import java.awt.swing.tree.*;
  31. import java.awt.accessibility.*;
  32.  
  33.  
  34. /**
  35.  * A control that displays a set of hierarchical data as an outline.
  36.  * A specific node can be identified either by a TreePath (an object
  37.  * that encapsulates a node and all of its ancestors), or by its
  38.  * display row, where each row in the display area displays one node.
  39.  * <p>
  40.  * An <i>expanded</i> node is one displays its children. A <i>collapsed</i>
  41.  * node is one which hides them. A <i>visible</i> node is one which
  42.  * is currently viewable in the display area.
  43.  * <p>
  44.  * If you are interested in knowing when the selection changes implement
  45.  * the TreeSelectionListener interface and add the instance using the
  46.  * method addTreeSelectionListener. valueChanged will be invoked when the
  47.  * selection changes, that is if the user clicks twice on the same
  48.  * node valueChanged will only be invoked once.
  49.  * <p>
  50.  * If you are interested in knowing either double clicks events or when
  51.  * a user clicks on a node, regardless of whether or not it was selected
  52.  * it is recommended you do the following:
  53.  * <pre>
  54.  * final JTree tree = ...;
  55.  *
  56.  * MouseListener ml = new MouseAdapter() {
  57.  *     public void <b>mouseClicked</b>(MouseEvent e) {
  58.  *         int selRow = tree.getRowForLocation(e.getX(), e.getY());
  59.  *         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
  60.  *         if(selRow != -1) {
  61.  *             if(e.getClickCount() == 1) {
  62.  *                 mySingleClick(selRow, selPath);
  63.  *             }
  64.  *             else if(e.getClickCount() == 2) {
  65.  *                 myDoubleClick(selRow, selPath);
  66.  *             }
  67.  *         }
  68.  *     }
  69.  * };
  70.  * tree.addMouseListener(ml);
  71.  *</pre>
  72.  * NOTE: This example obtains both the path and row, but you only need to
  73.  * get the one you're interested in.
  74.  * <p>
  75.  * See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/tree.html">How to Use Trees</a>
  76.  * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  77.  * for further documentation.
  78.  * <p>
  79.  * Warning: serialized objects of this class will not be compatible with
  80.  * future swing releases.  The current serialization support is appropriate
  81.  * for short term storage or RMI between Swing1.0 applications.  It will
  82.  * not be possible to load serialized Swing1.0 objects with future releases
  83.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  84.  * baseline for the serialized form of Swing objects.
  85.  *
  86.  * @beaninfo
  87.  *   attribute: isContainer false
  88.  *
  89.  * @version 1.70 02/12/98
  90.  * @author Rob Davis
  91.  * @author Ray Ryan
  92.  * @author Scott Violet
  93.  */
  94. public class JTree extends JComponent implements Scrollable, Accessible
  95. {
  96.     /**
  97.      * The model that defines the tree displayed by this object.
  98.      */
  99.     transient protected TreeModel                treeModel;
  100.  
  101.     /**
  102.      * Models the set of selected nodes in this tree.
  103.      */
  104.     transient protected TreeSelectionModel selectionModel;
  105.  
  106.     /**
  107.      * True if the root node is displayed, false if its children are
  108.      * the highest visible nodes.
  109.      */
  110.     protected boolean            rootVisible;
  111.  
  112.     /**
  113.      * The cell used to draw nodes. If null, the UI uses a default
  114.      * cellRenderer.
  115.      */
  116.     transient protected TreeCellRenderer        cellRenderer;
  117.  
  118.     /**
  119.      * Height to use for each display row. If this is <= 0 the renderer 
  120.      * determines the height for each row.
  121.      */
  122.     protected int               rowHeight;
  123.  
  124.     /**
  125.      * True if handles are displayed at the topmost level of the tree.
  126.      * <p>
  127.      * A handle is a small icon that displays adjacent to the node which 
  128.      * allows the user to click once to expand or collapse the node. A
  129.      * common interface shows a plus sign (+) for a node which can be
  130.      * expanded and a minus sign (-) for a node which can be collapsed.
  131.      * Handles are always shown for nodes below the topmost level.
  132.      * <p>
  133.      * If the <code>rootVisible</code> setting specifies that the root 
  134.      * node is to be displayed, then that is the only node at the topmost
  135.      * level. If the root node is not displayed, then all of its 
  136.      * children are at the topmost level of the tree. Handles are 
  137.      * always displayed for nodes other than the topmost.
  138.      * <p> 
  139.      * If the root node isn't visible, it is generally a good to make 
  140.      * this value true. Otherwise, the tree looks exactly like a list,
  141.      * and users may not know that the "list entries" are actually
  142.      * tree nodes.
  143.      *
  144.      * @see #rootVisible
  145.      */
  146.     protected boolean           showsRootHandles;
  147.  
  148.     /**
  149.      * Creates a new event and passed it off the selectionListeners.
  150.      */
  151.     protected TreeSelectionRedirector selectionRedirector;
  152.  
  153.     /**
  154.      * Editor for the entries.  Default is null (tree is not editable).
  155.      */
  156.     transient protected TreeCellEditor          cellEditor;
  157.  
  158.     /**
  159.      * Is the tree editable? Default is false.
  160.      */
  161.     protected boolean                 editable;
  162.  
  163.     /**
  164.      * Is this tree a large model? This is a code-optimization setting.
  165.      * A large model can be used when the cell height is the same for all
  166.      * nodes. The UI will then cache very little information and instead
  167.      * continually message the model. Without a large model the UI caches 
  168.      * most of the information, resulting in fewer method calls to the model.
  169.      * <p>
  170.      * This value is only a suggestion to the UI. Not all UIs will
  171.      * take advantage of it. Default value is false.
  172.      */
  173.     protected boolean                 largeModel;
  174.  
  175.     /**
  176.      * Number of rows to make visible at one time. This value is used for
  177.      * the Scrollable interface. It determines the preferred size of the 
  178.      * display area.
  179.      */
  180.     protected int                     visibleRowCount;
  181.  
  182.     /**
  183.      * If true, when editing is to be stopped by way of selection changing,
  184.      * data in tree changing or other means stopCellEditing is invoked, and
  185.      * changes are saved. If false, cancelCellEditing is invoked, and changes
  186.      * are discarded. Default is false.
  187.      */
  188.     protected boolean                 invokesStopCellEditing;
  189.  
  190.     //
  191.     // Bound propery names
  192.     //
  193.     /** Bound property name for cellRenderer. */
  194.     public final static String        CELL_RENDERER_PROPERTY = "cellRenderer";
  195.     /** Bound property name for treeModel. */
  196.     public final static String        TREE_MODEL_PROPERTY = "treeModel";
  197.     /** Bound property name for rootVisible. */
  198.     public final static String        ROOT_VISIBLE_PROPERTY = "rootVisible";
  199.     /** Bound property name for showsRootHandles. */
  200.     public final static String        SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
  201.     /** Bound property name for rowHeight. */
  202.     public final static String        ROW_HEIGHT_PROPERTY = "rowHeight";
  203.     /** Bound property name for cellEditor. */
  204.     public final static String        CELL_EDITOR_PROPERTY = "cellEditor";
  205.     /** Bound property name for editable. */
  206.     public final static String        EDITABLE_PROPERTY = "editable";
  207.     /** Bound property name for largeModel. */
  208.     public final static String        LARGE_MODEL_PROPERTY = "largeModel";
  209.     /** Bound property name for selectionModel. */
  210.     public final static String        SELECTION_MODEL_PROPERTY = "selectionModel";
  211.     /** Bound property name for visibleRowCount. */
  212.     public final static String        VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
  213.     /** Bound property name for messagesStopCellEditing. */
  214.     public final static String        INVOKES_STOP_CELL_EDITING_PROPERTY = "messagesStopCellEditing";
  215.  
  216.  
  217.     /**
  218.      * Creates and returns a sample TreeModel. Used primarily for beanbuilders.
  219.      * to show something interesting.
  220.      *
  221.      * @return the default TreeModel
  222.      */
  223.     protected static TreeModel getDefaultTreeModel() {
  224.         DefaultMutableTreeNode      root = new DefaultMutableTreeNode("root");
  225.         DefaultMutableTreeNode      parent, child;
  226.  
  227.         parent = root;
  228.         child = new DefaultMutableTreeNode("swing");
  229.         parent.add(child);
  230.         parent = child;
  231.         child = new DefaultMutableTreeNode("is");
  232.         parent.add(child);
  233.         parent = child;
  234.         child = new DefaultMutableTreeNode("cool");
  235.         parent.add(child);
  236.         return new DefaultTreeModel(root);
  237.     }
  238.  
  239.     /**
  240.      * Returns a TreeModel wrapping the specified object. If the object
  241.      * is:<ul>
  242.      * <li>an array of Objects,
  243.      * <li>a Hashtable, or
  244.      * <li>a Vector
  245.      * </ul>then a new root node is created with each of the incoming 
  246.      * objects as children. Otherwise, a new root is created with the 
  247.      * specified object as its value.
  248.      *
  249.      * @param value  the Object used as the foundation for the TreeModel
  250.      * @return a TreeModel wrapping the specified object
  251.      */
  252.     protected static TreeModel createTreeModel(Object value) {
  253.         DefaultMutableTreeNode           root;
  254.  
  255.         if((value instanceof Object[]) || (value instanceof Hashtable) ||
  256.            (value instanceof Vector)) {
  257.             root = new DefaultMutableTreeNode("root");
  258.             DynamicUtilTreeNode.createChildren(root, value);
  259.         }
  260.         else {
  261.             root = new DynamicUtilTreeNode("root", value);
  262.         }
  263.         return new DefaultTreeModel(root, false);
  264.     }
  265.  
  266.     /**
  267.      * Returns a JTree with a sample model.
  268.      *
  269.      * @return a JTree with the default model, which defines a leaf node
  270.      *         as any node without children.
  271.      * @see DefaultTreeModel#askAllowsChildren
  272.      */
  273.     public JTree() {
  274.         this(getDefaultTreeModel());
  275.     }
  276.  
  277.     /**
  278.      * Returns a JTree with each element of the specified array as the
  279.      * child of a new root node which is not displayed.
  280.      * By default, the tree defines a leaf node as any node without
  281.      * children.
  282.      *
  283.      * @param value  an array of Objects
  284.      * @return a JTree with the contents of the array as children of
  285.      *         the root node
  286.      * @see DefaultTreeModel#askAllowsChildren
  287.      */
  288.     public JTree(Object[] value) {
  289.         this(createTreeModel(value));
  290.         this.setRootVisible(false);
  291.         this.setShowsRootHandles(true);
  292.     }
  293.  
  294.     /**
  295.      * Returns a JTree with each element of the specified Vector as the
  296.      * child of a new root node which is not displayed. By default, the
  297.      * tree defines a leaf node as any node without children.
  298.      *
  299.      * @param value  a Vector
  300.      * @return a JTree with the contents of the Vector as children of
  301.      *         the root node
  302.      * @see DefaultTreeModel#askAllowsChildren
  303.      */
  304.     public JTree(Vector value) {
  305.         this(createTreeModel(value));
  306.         this.setRootVisible(false);
  307.         this.setShowsRootHandles(true);
  308.     }
  309.  
  310.     /**
  311.      * Returns a JTree created from a Hashtable which does not display
  312.      * the root. Each value-half of the key/value pairs in the HashTable
  313.      * becomes a child of the new root node. By default, the tree defines
  314.      * a leaf node as any node without children.
  315.      *
  316.      * @param value  a Hashtable
  317.      * @return a JTree with the contents of the Hashtable as children of
  318.      *         the root node
  319.      * @see DefaultTreeModel#askAllowsChildren
  320.      */
  321.     public JTree(Hashtable value) {
  322.         this(createTreeModel(value));
  323.         this.setRootVisible(false);
  324.         this.setShowsRootHandles(true);
  325.     }
  326.  
  327.     /**
  328.      * Returns a JTree with the specified TreeNode as its root which is 
  329.      * not displayed. By default, the tree defines a leaf node as any node
  330.      * without children.
  331.      *
  332.      * @param root  a TreeNode object
  333.      * @return a JTree with the specified root node
  334.      * @see DefaultTreeModel#askAllowsChildren
  335.      */
  336.     public JTree(TreeNode root) {
  337.         this(root, false);
  338.     }
  339.  
  340.     /**
  341.      * Returns a JTree with the specified TreeNode as its root, which 
  342.      * displays the root node and which decides whether a node is a 
  343.      * leaf node in the specified manner.
  344.      *
  345.      * @param root  a TreeNode object
  346.      * @param asksAllowsChildren  if false, any node without children is a 
  347.      *              leaf node. If true, only nodes that do not allow 
  348.      *              children are leaf nodes.
  349.      * @return a JTree with the specified root node
  350.      * @see DefaultTreeModel#askAllowsChildren
  351.      */
  352.     public JTree(TreeNode root, boolean asksAllowsChildren) {
  353.         this(new DefaultTreeModel(root, asksAllowsChildren));
  354.     }
  355.  
  356.     /**
  357.      * Returns an instance of JTree which displays the root node 
  358.      * -- the tree is created using the specified data model.
  359.      *
  360.      * @param newModel  the TreeModel to use as the data model
  361.      * @return a JTree based on the TreeModel
  362.      */
  363.     public JTree(TreeModel newModel) {
  364.         super();
  365.         setLayout(null);
  366.         rowHeight = 16;
  367.         visibleRowCount = 20;
  368.         rootVisible = true;
  369.         selectionModel = new DefaultTreeSelectionModel();
  370.         cellRenderer = null;
  371.         updateUI();
  372.         setModel(newModel);
  373.     }
  374.  
  375.     /**
  376.      * Returns the L&F object that renders this component.
  377.      *
  378.      * @return the TreeUI object that renders this component
  379.      */
  380.     public TreeUI getUI() {
  381.         return (TreeUI)ui;
  382.     }
  383.  
  384.     /**
  385.      * Sets the L&F object that renders this component.
  386.      *
  387.      * @param ui  the TreeUI L&F object
  388.      * @see UIDefaults#getUI
  389.      */
  390.     public void setUI(TreeUI ui) {
  391.         if ((TreeUI)this.ui != ui) {
  392.             super.setUI(ui);
  393.             repaint();
  394.         }
  395.     }
  396.  
  397.     /**
  398.      * Notification from the UIManager that the L&F has changed. 
  399.      * Replaces the current UI object with the latest version from the 
  400.      * UIManager.
  401.      *
  402.      * @see JComponent#updateUI
  403.      */
  404.     public void updateUI() {
  405.         setUI((TreeUI)UIManager.getUI(this));
  406.         invalidate();
  407.     }
  408.  
  409.  
  410.     /**
  411.      * Returns the name of the L&F class that renders this component.
  412.      *
  413.      * @return "TreeUI"
  414.      * @see JComponent#getUIClassID
  415.      * @see UIDefaults#getUI
  416.      */
  417.     public String getUIClassID() {
  418.         return "TreeUI";
  419.     }
  420.  
  421.  
  422.     /**
  423.      * Returns the current TreeCellRenderer that is rendering each cell.
  424.      *
  425.      * @return the TreeCellRenderer that is rendering each cell
  426.      */
  427.     public TreeCellRenderer getCellRenderer() {
  428.         return cellRenderer;
  429.     }
  430.  
  431.     /**
  432.      * Sets the TreeCellRenderer that will be used to draw each cell.
  433.      *
  434.      * @param x  the TreeCellRenderer that is to render each cell
  435.      * @beaninfo
  436.      *        bound: true
  437.      *  description: The TreeCellRenderer that will be used to draw
  438.      *               each cell.
  439.      */
  440.     public void setCellRenderer(TreeCellRenderer x) {
  441.         TreeCellRenderer oldValue = cellRenderer;
  442.  
  443.         cellRenderer = x;
  444.         firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, cellRenderer);
  445.         invalidate();
  446.     }
  447.  
  448.     /**
  449.       * Determines whether the tree is editable. Fires a property
  450.       * change event if the new setting is different from the existing
  451.       * setting.
  452.       *
  453.       * @param flag  a boolean value, true if the tree is editable
  454.       * @beaninfo
  455.       *        bound: true
  456.       *  description: Whether the tree is ediable.
  457.       */
  458.     public void setEditable(boolean flag) {
  459.         boolean                 oldValue = this.editable;
  460.  
  461.         this.editable = flag;
  462.         firePropertyChange(EDITABLE_PROPERTY, oldValue, flag);
  463.         if (accessibleContext != null) {
  464.             accessibleContext.firePropertyChange(
  465.                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 
  466.                 (oldValue ? AccessibleState.EDITABLE : null),
  467.                 (flag ? AccessibleState.EDITABLE : null));
  468.         }
  469.     }
  470.  
  471.     /**
  472.      * Returns true if the tree is editable.
  473.      *
  474.      * @return true if the tree is editable.
  475.      */
  476.     public boolean isEditable() {
  477.         return editable;
  478.     }
  479.  
  480.     /**
  481.      * Sets the cell editor.  A null value implies that the
  482.      * tree cannot be edited.  If this represents a change in the
  483.      * cellEditor, the propertyChange method is invoked on all
  484.      * listeners.
  485.      *
  486.      * @param cellEditor the TreeCellEditor to use
  487.      * @beaninfo
  488.      *        bound: true
  489.      *  description: The cell editor. A null value implies the tree
  490.      *               cannot be edited.
  491.      */
  492.     public void setCellEditor(TreeCellEditor cellEditor) {
  493.         TreeCellEditor        oldEditor = this.cellEditor;
  494.  
  495.         this.cellEditor = cellEditor;
  496.         firePropertyChange(CELL_EDITOR_PROPERTY, oldEditor, cellEditor);
  497.         invalidate();
  498.     }
  499.  
  500.     /**
  501.      * Returns the editor used to edit entries in the tree.
  502.      *
  503.      * @return the TreeCellEditor in use, or null if the tree cannot
  504.      *         be edited
  505.      */
  506.     public TreeCellEditor getCellEditor() {
  507.         return cellEditor;
  508.     }
  509.  
  510.     /**
  511.      * Returns the TreeModel that is providing the data.
  512.      *
  513.      * @return the TreeModel that is providing the data
  514.      */
  515.     public TreeModel getModel() {
  516.         return treeModel;
  517.     }
  518.  
  519.     /**
  520.      * Sets the TreeModel that will provide the data.
  521.      *
  522.      * @param newModel the TreeModel that is to provide the data
  523.      * @beaninfo
  524.      *        bound: true
  525.      *  description: The TreeModel that will provide the data.
  526.      */
  527.     public void setModel(TreeModel newModel) {
  528.         TreeModel oldModel = treeModel;
  529.         
  530.         treeModel = newModel;
  531.         firePropertyChange(TREE_MODEL_PROPERTY, oldModel, treeModel);
  532.         invalidate();
  533.     }
  534.  
  535.     /**
  536.      * Returns true if the root node of the tree is displayed.
  537.      *
  538.      * @return true if the root node of the tree is displayed
  539.      * @see #rootVisible
  540.      */
  541.     public boolean isRootVisible() {
  542.         return rootVisible;
  543.     }
  544.  
  545.     /**
  546.      * Determines whether or not the root node from
  547.      * the TreeModel is visible.
  548.      *
  549.      * @param rootVisible true if the root node of the tree is to be displayed
  550.      * @see #rootVisible
  551.      * @beaninfo
  552.      *        bound: true
  553.      *  description: Whether or not the root node 
  554.      *               from the TreeModel is visible.
  555.      */
  556.     public void setRootVisible(boolean rootVisible) {
  557.         boolean                oldValue = this.rootVisible;
  558.  
  559.         this.rootVisible = rootVisible;
  560.         firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, this.rootVisible);
  561.         if (accessibleContext != null) {
  562.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  563.         }
  564.     }
  565.  
  566.     /**
  567.      * Determines whether the node handles are to be displayed.
  568.      * 
  569.      * @param newValue true if root handles are to be displayed
  570.      * @see #showsRootHandles
  571.      * @beaninfo
  572.      *        bound: true
  573.      *  description: Whether the node handles are to be
  574.      *               displayed.
  575.      */
  576.     public void setShowsRootHandles(boolean newValue) {
  577.         boolean                oldValue = showsRootHandles;
  578.  
  579.         showsRootHandles = newValue;
  580.         firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue,
  581.                            showsRootHandles);
  582.         if (accessibleContext != null) {
  583.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  584.         }
  585.         invalidate();
  586.     }
  587.  
  588.     /**
  589.      * Returns true if handles for the root nodes are displayed.
  590.      * 
  591.      * @return true if root handles are displayed
  592.      * @see #showsRootHandles
  593.      */
  594.     public boolean getShowsRootHandles()
  595.     {
  596.         return showsRootHandles;
  597.     }
  598.  
  599.     /**
  600.      * Sets the height of each cell.  If the specified value
  601.      * is less than or equal to zero the current cell renderer is
  602.      * queried for each row's height.
  603.      *
  604.      * @param rowHeight the height of each cell, in pixels
  605.      * @beaninfo
  606.      *        bound: true
  607.      *  description: The height of each cell.
  608.      */
  609.     public void setRowHeight(int rowHeight)
  610.     {
  611.         int                oldValue = this.rowHeight;
  612.  
  613.         this.rowHeight = rowHeight;
  614.         firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, this.rowHeight);
  615.         invalidate();
  616.     }
  617.  
  618.     /**
  619.      * Returns the height of each row.  If the returned value is less than
  620.      * or equal to 0 the height for each row is determined by the
  621.      * renderer.
  622.      *
  623.      * @param the height of each cell, in pixels. Zero or negative if the
  624.      *        height of each row is determined by the tree cell renderer
  625.      */
  626.     public int getRowHeight()
  627.     {
  628.         return rowHeight;
  629.     }
  630.  
  631.     /**
  632.      * Returns true if the height of each display row is a fixed size.
  633.      *
  634.      * @return true if the height of each row is a fixed size
  635.      */
  636.     public boolean isFixedRowHeight()
  637.     {
  638.         return (rowHeight > 0);
  639.     }
  640.  
  641.     /**
  642.      * Specifies whether the UI should use a large model.
  643.      * (Not all UIs will implement this.) Fires a property change
  644.      * for the LARGE_MODEL_PROPERTY.
  645.      * 
  646.      * @param newValue true to suggest a large model to the UI
  647.      * @see #largeModel
  648.      * @beaninfo
  649.      *        bound: true
  650.      *  description: Whether the UI should use a 
  651.      *               large model.
  652.      */
  653.     public void setLargeModel(boolean newValue) {
  654.         boolean                oldValue = largeModel;
  655.  
  656.         largeModel = newValue;
  657.         firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, newValue);
  658.     }
  659.  
  660.     /**
  661.      * Returns true if the tree is configured for a large model.
  662.      * 
  663.      * @return true if a large model is suggested
  664.      * @see #largeModel
  665.      */
  666.     public boolean isLargeModel() {
  667.         return largeModel;
  668.     }
  669.  
  670.     /**
  671.      * Determines what happens when editing is interrupted by selecting
  672.      * another node in the tree, a change in the tree's data, or by some
  673.      * other means. Fires a property change for the 
  674.      * INVOKES_STOP_CELL_EDITING_PROPERTY.
  675.      *
  676.      * @param newValue true means that stopCellEditing is invoked when
  677.      *        editing is interruped, and data is saved. False means that
  678.      *        cancelCellEditing is invoked, and changes are lost.
  679.      * @beaninfo
  680.      *        bound: true
  681.      *  description: Determines what happens when editing is interrupted,
  682.      *               selecting another node in the tree, a change in the
  683.      *               tree's data, or some other means.
  684.      */
  685.     public void setInvokesStopCellEditing(boolean newValue) {
  686.         boolean                  oldValue = invokesStopCellEditing;
  687.  
  688.         invokesStopCellEditing = newValue;
  689.         firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, oldValue,
  690.                            newValue);
  691.     }
  692.  
  693.     /**
  694.      * Returns the indicator that tells what happens when editing is 
  695.      * interrupted.
  696.      *
  697.      * @return the indicator that tells what happens when editing is 
  698.      *         interrupted
  699.      * @see #setInvokesStopCellEditing
  700.      */
  701.     public boolean getInvokesStopCellEditing() {
  702.         return invokesStopCellEditing;
  703.     }
  704.  
  705.     /**
  706.      * Returns <code>isEditable</code>. This is invoked from the UI before
  707.      * editing begins to insure that the given path can be edited. This
  708.      * is provided as an entry point for subclassers to add filtered
  709.      * editing without having to resort to creating a new editor.
  710.      *
  711.      * @return true if every parent node and the node itself is editabled
  712.      * @see #isEditable
  713.      */
  714.     public boolean isPathEditable(TreePath path) {
  715.         return isEditable();
  716.     }
  717.  
  718.     /**
  719.      * Overrides JComponent's getToolTipText method in order to allow 
  720.      * renderer's tips to be used if it has text set.
  721.      * <p>
  722.      * NOTE: For JTree to properly display tooltips of its renderers
  723.      *       JTree must be a registered component with the ToolTipManager.
  724.      *       This can be done by invoking
  725.      *       <code>ToolTipManager.sharedInstance().registerComponent(tree)</code>.
  726.      *       This is not done automaticly!
  727.      *
  728.      * @param event the MouseEvent that initiated the ToolTip display
  729.      */
  730.     public String getToolTipText(MouseEvent event) {
  731.         if(event != null) {
  732.             Point p = event.getPoint();
  733.             int selRow = getRowForLocation(p.x, p.y);
  734.             TreeCellRenderer       r = getCellRenderer();
  735.  
  736.             if(selRow != -1 && r != null) {
  737.                 TreePath     path = getPathForRow(selRow);
  738.                 Object       lastPath = path.getLastPathComponent();
  739.                 Component    rComponent = r.getTreeCellRendererComponent
  740.                     (this, lastPath, isRowSelected(selRow),
  741.                      isExpanded(selRow), getModel().isLeaf(lastPath), selRow,
  742.                      true);
  743.  
  744.                 if(rComponent instanceof JComponent) {
  745.                     MouseEvent      newEvent;
  746.                     Rectangle       pathBounds = getPathBounds(path);
  747.  
  748.                     p.translate(-pathBounds.x, -pathBounds.y);
  749.                     newEvent = new MouseEvent(rComponent, event.getID(),
  750.                                           event.getWhen(),
  751.                                               event.getModifiers(),
  752.                                               p.x, p.y, event.getClickCount(),
  753.                                               event.isPopupTrigger());
  754.                     
  755.                     return ((JComponent)rComponent).getToolTipText(newEvent);
  756.                 }
  757.             }
  758.         }
  759.         return null;
  760.     }
  761.     
  762.     /**
  763.      * Called by the renderers to convert the specified value to
  764.      * text. This implementation returns value.toString(), ignoring
  765.      * all other arguments. To control the conversion, subclass this 
  766.      * method and use any of the arguments you need.
  767.      * 
  768.      * @param value the Object to convert to text
  769.      * @param selected true if the node is selected
  770.      * @param expanded true if the node is expanded
  771.      * @param leaf  true if the node is a leaf node
  772.      * @param row  an int specifying the node's display row, where 0 is 
  773.      *             the first row in the display
  774.      * @param hasFocus true if the node has the focus
  775.      * @return the String representation of the node's value
  776.      */
  777.     public String convertValueToText(Object value, boolean selected,
  778.                                      boolean expanded, boolean leaf, int row,
  779.                                      boolean hasFocus) {
  780.         if(value != null)
  781.             return value.toString();
  782.         return "";
  783.     }
  784.  
  785.     //
  786.     // The following are convenience methods that get forwarded to the
  787.     // current TreeUI.
  788.     //
  789.  
  790.     /**
  791.      * Returns the number of rows that are currently being displayed.
  792.      *
  793.      * @return the number of rows that are being displayed
  794.      */
  795.     public int getRowCount() {
  796.         TreeUI            tree = getUI();
  797.  
  798.         if(tree != null)
  799.             return tree.getRowCount();
  800.         return 0;
  801.     }
  802.  
  803.     /** 
  804.      * Selects the node identified by the specified path.  If any
  805.      * component of the path is hidden (under a collapsed node), it is 
  806.      * exposed (made viewable).
  807.      *
  808.      * @param path the TreePath specifying the node to select
  809.      */
  810.     public void setSelectionPath(TreePath path) {
  811.         getSelectionModel().setSelectionPath(path);
  812.         if (accessibleContext != null) {
  813.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  814.         }
  815.     }
  816.  
  817.     /** 
  818.      * Selects the nodes identified by the specified array of paths.
  819.      * If any component in any of the paths is hidden (under a collapsed
  820.      * node), it is exposed (made viewable).
  821.      *
  822.      * @param paths an array of TreePath objects that specifies the nodes
  823.      *        to select
  824.      */
  825.     public void setSelectionPaths(TreePath[] paths) {
  826.         getSelectionModel().setSelectionPaths(paths);
  827.         if (accessibleContext != null) {
  828.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  829.         }
  830.     }
  831.  
  832.     /**
  833.      * Selects the node at the specified row in the display.
  834.      *
  835.      * @param row  the row to select, where 0 is the first row in
  836.      *             the display
  837.      */
  838.     public void setSelectionRow(int row) {
  839.         int[]             rows = { row };
  840.  
  841.         setSelectionRows(rows);
  842.     }
  843.  
  844.     /**
  845.      * Selects the nodes corresponding to each of the specified rows
  846.      * in the display.
  847.      * 
  848.      * @param rows  an array of ints specifying the rows to select,
  849.      *              where 0 indicates the first row in the display
  850.      */
  851.     public void setSelectionRows(int[] rows) {
  852.         TreeUI               ui = getUI();
  853.  
  854.         if(ui != null && rows != null) {
  855.             int                  numRows = rows.length;
  856.             TreePath[]           paths = new TreePath[numRows];
  857.  
  858.             for(int counter = 0; counter < numRows; counter++)
  859.                 paths[counter] = ui.getPathForRow(rows[counter]);
  860.             setSelectionPaths(paths);
  861.         }
  862.     }
  863.  
  864.     /**
  865.      * Adds the node identified by the specified TreePath to the current
  866.      * selection. If any component of the path isn't visible, it is 
  867.      * made visible.
  868.      *
  869.      * @param path the TreePath to add
  870.      */
  871.     public void addSelectionPath(TreePath path) {
  872.         getSelectionModel().addSelectionPath(path);
  873.         if (accessibleContext != null) {
  874.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  875.         }
  876.     }
  877.  
  878.     /**
  879.      * Adds each path in the array of paths to the current selection.  If
  880.      * any component of any of the paths isn't visible, it is
  881.      * made visible.
  882.      *
  883.      * @param paths an array of TreePath objects that specifies the nodes
  884.      *              to add
  885.      */
  886.     public void addSelectionPaths(TreePath[] paths) {
  887.         getSelectionModel().addSelectionPaths(paths);
  888.         if (accessibleContext != null) {
  889.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  890.         }
  891.     }
  892.  
  893.     /**
  894.      * Adds the path at the specified row to the current selection.
  895.      *
  896.      * @param row  an int specifying the row of the node to add,
  897.      *             where 0 is the first row in the display
  898.      */
  899.     public void addSelectionRow(int row) {
  900.         int[]      rows = { row };
  901.  
  902.         addSelectionRows(rows);
  903.     }
  904.  
  905.     /**
  906.      * Adds the paths at each of the specified rows to the current selection.
  907.      * 
  908.      * @param rows  an array of ints specifying the rows to add,
  909.      *              where 0 indicates the first row in the display
  910.      */
  911.     public void addSelectionRows(int[] rows) {
  912.         TreeUI             ui = getUI();
  913.  
  914.         if(ui != null && rows != null) {
  915.             int                  numRows = rows.length;
  916.             TreePath[]           paths = new TreePath[numRows];
  917.  
  918.             for(int counter = 0; counter < numRows; counter++)
  919.                 paths[counter] = ui.getPathForRow(rows[counter]);
  920.             addSelectionPaths(paths);
  921.         }
  922.     }
  923.  
  924.     /**
  925.      * Returns the last path component in the first node of the current 
  926.      * selection.
  927.      *
  928.      * @return the last Object in the first selected node's TreePath,
  929.      *         or null if nothing is selected
  930.      * @see TreePath#getLastPathComponent
  931.      */
  932.     public Object getLastSelectedPathComponent() {
  933.         TreePath     selPath = getSelectionModel().getSelectionPath();
  934.  
  935.         if(selPath != null)
  936.             return selPath.getLastPathComponent();
  937.         return null;
  938.     }
  939.  
  940.     /**
  941.      * Returns the path to the first selected node.
  942.      *
  943.      * @return the TreePath for the first selected node, or null if
  944.      *         nothing is currently selected
  945.      */
  946.     public TreePath getSelectionPath() {
  947.         return getSelectionModel().getSelectionPath();
  948.     }
  949.  
  950.     /**
  951.      * Returns the paths of all selected values.
  952.      *
  953.      * @return an array of TreePath objects indicating the selected
  954.      *         nodes, or null if nothing is currently selected.
  955.      */
  956.     public TreePath[] getSelectionPaths() {
  957.         return getSelectionModel().getSelectionPaths();
  958.     }
  959.  
  960.     /**
  961.      * Returns all of the currently selected rows.
  962.      *
  963.      * @return an array of ints that identifies all currently selected rows
  964.      *         where 0 is the first row in the display
  965.      */
  966.     public int[] getSelectionRows() {
  967.         return getSelectionModel().getSelectionRows();
  968.     }
  969.  
  970.     /**
  971.      * Returns the number of nodes selected.
  972.      *
  973.      * @return the number of nodes selected
  974.      */
  975.     public int getSelectionCount() {
  976.         return selectionModel.getSelectionCount();
  977.     }
  978.  
  979.     /**
  980.      * Gets the first selected row.
  981.      *
  982.      * @return an int designating the first selected row, where 0 is the 
  983.      *         first row in the display
  984.      */
  985.     public int getMinSelectionRow() {
  986.         return getSelectionModel().getMinSelectionRow();
  987.     }
  988.  
  989.     /**
  990.      * Gets the last selected row.
  991.      *
  992.      * @return an int designating the last selected row, where 0 is the 
  993.      *         first row in the display
  994.      */
  995.     public int getMaxSelectionRow() {
  996.         return getSelectionModel().getMaxSelectionRow();
  997.     }
  998.  
  999.     /**
  1000.      * Returns the row index of the last node added to the selection.
  1001.      *
  1002.      * @return an int giving the row index of the last node added to the
  1003.      *         selection, where 0 is the first row in the display
  1004.      */
  1005.     public int getLeadSelectionRow() {
  1006.         return getSelectionModel().getLeadSelectionRow();
  1007.     }
  1008.  
  1009.     /**
  1010.      * Returns the path of the last node added to the selection.
  1011.      *
  1012.      * @return the TreePath of the last node added to the selection.
  1013.      */
  1014.     public TreePath getLeadSelectionPath() {
  1015.         return getSelectionModel().getLeadSelectionPath();
  1016.     }
  1017.  
  1018.     /**
  1019.      * Returns true if the item identified by the path is currently selected.
  1020.      *
  1021.      * @param path a TreePath identifying a node
  1022.      * @return true if the node is selected
  1023.      */
  1024.     public boolean isPathSelected(TreePath path) {
  1025.         return getSelectionModel().isPathSelected(path);
  1026.     }
  1027.  
  1028.     /**
  1029.      * Returns true if the node identitifed by row is selected.
  1030.      *
  1031.      * @param row  an int specifying a display row, where 0 is the first
  1032.      *             row in the display
  1033.      * @return true if the node is selected
  1034.      */
  1035.     public boolean isRowSelected(int row) {
  1036.         return getSelectionModel().isRowSelected(row);
  1037.     }
  1038.  
  1039.     /**
  1040.      * Returns true if the node identified by the path is currently expanded,
  1041.      * 
  1042.      * @param path  the TreePath specifying the node to check
  1043.      * @return false if any of the nodes in the node's path are collapsed, 
  1044.      *               true if all nodes in the path are expanded
  1045.      */
  1046.     public boolean isExpanded(TreePath path) {
  1047.         TreeUI                  tree = getUI();
  1048.  
  1049.         if(tree != null)
  1050.             return tree.isExpanded(path);
  1051.         return false;
  1052.     }
  1053.  
  1054.     /**
  1055.      * Returns true if the node at the specified display row is currently
  1056.      * expanded.
  1057.      * 
  1058.      * @param row  the row to check, where 0 is the first row in the 
  1059.      *             display
  1060.      * @return true if the node is currently expanded, otherwise false
  1061.      */
  1062.     public boolean isExpanded(int row) {
  1063.         TreeUI                  tree = getUI();
  1064.  
  1065.         if(tree != null)
  1066.             return tree.isExpanded(row);
  1067.         return false;
  1068.     }
  1069.  
  1070.     /**
  1071.      * Returns true if the value identified by path is currently collapsed,
  1072.      * this will return false if any of the values in path are currently
  1073.      * not being displayed.
  1074.      * 
  1075.      * @param path  the TreePath to check
  1076.      * @return true if any of the nodes in the node's path are collapsed, 
  1077.      *               false if all nodes in the path are expanded
  1078.      */
  1079.     public boolean isCollapsed(TreePath path) {
  1080.         TreeUI                  tree = getUI();
  1081.  
  1082.         if(tree != null)
  1083.             return tree.isCollapsed(path);
  1084.         return false;
  1085.     }
  1086.  
  1087.     /**
  1088.      * Returns true if the node at the specified display row is collapsed.
  1089.      * 
  1090.      * @param row  the row to check, where 0 is the first row in the 
  1091.      *             display
  1092.      * @return true if the node is currently collapsed, otherwise false
  1093.      */
  1094.     public boolean isCollapsed(int row) {
  1095.         TreeUI                  tree = getUI();
  1096.  
  1097.         if(tree != null)
  1098.             return tree.isCollapsed(row);
  1099.         return false;
  1100.     }
  1101.  
  1102.     /**
  1103.      * Ensures that the node identified by path is currently visible.
  1104.      *
  1105.      * @param path  the TreePath to make visible
  1106.      */
  1107.     public void makeVisible(TreePath path) {
  1108.         TreeUI                   tree = getUI();
  1109.  
  1110.         if(tree != null) {
  1111.             tree.makeVisible(path);
  1112.             if (accessibleContext != null) {
  1113.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1114.             }
  1115.         }
  1116.     }
  1117.  
  1118.     /**
  1119.      * Returns true if the value identified by path is currently visible,
  1120.      * false otherwise.
  1121.      *
  1122.      * @return true if the node is visible, otherwise false
  1123.      */
  1124.     public boolean isVisible(TreePath path) {
  1125.         TreeUI                   tree = getUI();
  1126.  
  1127.         if(tree != null)
  1128.             return tree.isVisible(path);
  1129.         return false;
  1130.     }
  1131.  
  1132.     /**
  1133.      * Returns the Rectangle that the specified node will be drawn
  1134.      * into. Returns null if any component in the path is hidden
  1135.      * (under a collapsed parent).
  1136.      * <p>
  1137.      * Note:<br>
  1138.      * This method returns a valid rectangle, even if the specified
  1139.      * node is not currently displayed.
  1140.      *
  1141.      * @param path the TreePath identifying the node
  1142.      * @return the Rectangle the node is drawn in, or null 
  1143.      */
  1144.     public Rectangle getPathBounds(TreePath path) {
  1145.         TreeUI                   tree = getUI();
  1146.  
  1147.         if(tree != null)
  1148.             return tree.getPathBounds(path);
  1149.         return null;
  1150.     }
  1151.  
  1152.     /**
  1153.      * Returns the Rectangle that the node at the specified row is
  1154.      * drawn in.
  1155.      *
  1156.      * @param row  the row to be drawn, where 0 is the first row in the 
  1157.      *             display
  1158.      * @return the Rectangle the node is drawn in 
  1159.      */
  1160.     public Rectangle getRowBounds(int row) {
  1161.         TreeUI                    tree = getUI();
  1162.  
  1163.         if(tree != null)
  1164.             return tree.getRowBounds(row);
  1165.         return null;
  1166.     }
  1167.  
  1168.     /**
  1169.      * Makes sure all the path components in path are expanded (except
  1170.      * for the last path component) and scrolls so that the 
  1171.      * node identified by the path is visible.
  1172.      * 
  1173.      * @param path  the TreePath identifying the node to bring into view
  1174.      */
  1175.     public void scrollPathToVisible(TreePath path) {
  1176.         TreeUI                 tree = getUI();
  1177.  
  1178.         if(tree != null) {
  1179.             tree.scrollPathToVisible(path);
  1180.             if (accessibleContext != null) {
  1181.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1182.             }
  1183.         }
  1184.     }
  1185.  
  1186.     /**
  1187.      * Scrolls the item identified by row to be visible. The minimum
  1188.      * of amount of scrolling necessary to bring the row into view
  1189.      * is performed. Only works when this JTree is contained in a
  1190.      * JSrollPane.
  1191.      *
  1192.      * @param row  an int specifying the row to scroll, where 0 is the
  1193.      *             first row in the display
  1194.      */
  1195.     public void scrollRowToVisible(int row) {
  1196.         TreeUI                  tree = getUI();
  1197.  
  1198.         if(tree != null) {
  1199.             tree.scrollRowToVisible(row);
  1200.             if (accessibleContext != null) {
  1201.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1202.             }
  1203.         }
  1204.     }
  1205.  
  1206.     /**
  1207.      * Returns the path for the specified row.
  1208.      * <!-->If row is not visible null is returned.<-->
  1209.      *
  1210.      * @param row  an int specifying a row
  1211.      * @return the TreePath to the specified node, null if
  1212.      *         row < 0 or row > getRowCount()
  1213.      */
  1214.     public TreePath getPathForRow(int row) {
  1215.         TreeUI                  tree = getUI();
  1216.  
  1217.         if(tree != null)
  1218.             return tree.getPathForRow(row);
  1219.         return null;
  1220.     }
  1221.  
  1222.     /**
  1223.      * Returns the row that displays the node identified by the specified
  1224.      * path. 
  1225.      * 
  1226.      * @param path  the TreePath identifying a node
  1227.      * @return an int specifying the display row, where 0 is the first
  1228.      *         row in the display, or -1 if any of the elements in path
  1229.      *         are hidden under a collapsed parent.
  1230.      */
  1231.     public int getRowForPath(TreePath path) {
  1232.         TreeUI                  tree = getUI();
  1233.  
  1234.         if(tree != null)
  1235.             return tree.getRowForPath(path);
  1236.         return -1;
  1237.     }
  1238.  
  1239.     /**
  1240.      * Ensures that the node identified by the specified path is 
  1241.      * expanded and visible.
  1242.      * 
  1243.      * @param path  the TreePath identifying a node
  1244.      */
  1245.     public void expandPath(TreePath path) {
  1246.         TreeUI                  tree = getUI();
  1247.  
  1248.         if(tree != null) {
  1249.             tree.expandPath(path);
  1250.             if (accessibleContext != null) {
  1251.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1252.             }
  1253.         }
  1254.     }
  1255.  
  1256.     /**
  1257.      * Ensures that the node in the specified row is expanded.
  1258.      *
  1259.      * @param row  an int specifying a display row, where 0 is the
  1260.      *             first row in the display
  1261.      */
  1262.     public void expandRow(int row) {
  1263.         TreeUI                  tree = getUI();
  1264.  
  1265.         if(tree != null) {
  1266.             tree.expandRow(row);
  1267.             if (accessibleContext != null) {
  1268.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1269.             }
  1270.         }
  1271.     }
  1272.  
  1273.     /**
  1274.      * Ensures that the node identified by the specified path is 
  1275.      * collapsed and visible.
  1276.      * 
  1277.      * @param path  the TreePath identifying a node
  1278.       */
  1279.     public void collapsePath(TreePath path) {
  1280.         TreeUI                  tree = getUI();
  1281.  
  1282.         if(tree != null) {
  1283.             tree.collapsePath(path);
  1284.             if (accessibleContext != null) {
  1285.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1286.             }
  1287.         }
  1288.     }
  1289.  
  1290.     /**
  1291.      * Ensures that the node in the specified row is collapsed.
  1292.      *
  1293.      * @param row  an int specifying a display row, where 0 is the
  1294.      *             first row in the display
  1295.       */
  1296.     public void collapseRow(int row) {
  1297.         TreeUI                  tree = getUI();
  1298.  
  1299.         if(tree != null) {
  1300.             tree.collapseRow(row);
  1301.             if (accessibleContext != null) {
  1302.                 ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1303.             }
  1304.         }
  1305.     }
  1306.  
  1307.     /**
  1308.      * Returns the path for the node at the specified location.
  1309.      *
  1310.      * @param x an int giving the number of pixels horizontally from
  1311.      *          the left edge of the display area, minus any left margin
  1312.      * @param y an int giving the number of pixels vertically from
  1313.      *          the top of the display area, minus any top margin
  1314.      * @return  the TreePath for the node at that location
  1315.      */
  1316.     public TreePath getPathForLocation(int x, int y) {
  1317.         TreePath          closestPath = getClosestPathForLocation(x, y);
  1318.  
  1319.         if(closestPath != null) {
  1320.             Rectangle       pathBounds = getPathBounds(closestPath);
  1321.  
  1322.             if(x >= pathBounds.x && x < (pathBounds.x + pathBounds.width) &&
  1323.                y >= pathBounds.y && y < (pathBounds.y + pathBounds.height))
  1324.                 return closestPath;
  1325.         }
  1326.         return null;
  1327.     }
  1328.  
  1329.     /**
  1330.      * Returns the row for the specified location. 
  1331.      *
  1332.      * @param x an int giving the number of pixels horizontally from
  1333.      *          the left edge of the display area, minus any left margin
  1334.      * @param y an int giving the number of pixels vertically from
  1335.      *          the top of the display area, minus any top margin
  1336.      * @return the row corresponding to the location, or -1 if the
  1337.      *         location is not within the bounds of a displayed cell
  1338.      * @see #closestRowForLocation
  1339.      */
  1340.     public int getRowForLocation(int x, int y) {
  1341.         int             closestRow = getClosestRowForLocation(x, y);
  1342.  
  1343.         if(closestRow != -1) {
  1344.             Rectangle       rowBounds = getRowBounds(closestRow);
  1345.  
  1346.             if(x >= rowBounds.x && x < (rowBounds.x + rowBounds.width) &&
  1347.                y >= rowBounds.y && y < (rowBounds.y + rowBounds.height))
  1348.                 return closestRow;
  1349.         }
  1350.         return -1;
  1351.     }
  1352.  
  1353.     /**
  1354.      * Returns the path to the node that is closest to x,y.  If
  1355.      * nothing is currently visible, or there is no model, returns
  1356.      * null, otherwise it always returns a valid path.  To test if
  1357.      * the node is exactly at x, y, get the node's bounds and
  1358.      * test x, y against that.
  1359.      *
  1360.      * @param x an int giving the number of pixels horizontally from
  1361.      *          the left edge of the display area, minus any left margin
  1362.      * @param y an int giving the number of pixels vertically from
  1363.      *          the top of the display area, minus any top margin
  1364.      * @return  the TreePath for the node closest to that location,
  1365.      *          null if nothing is visible or there is no model
  1366.      *
  1367.      * @see #getPathForLocation
  1368.      * @see #getPathBounds
  1369.      */
  1370.     public TreePath getClosestPathForLocation(int x, int y) {
  1371.         TreeUI                  tree = getUI();
  1372.  
  1373.         if(tree != null)
  1374.             return tree.getClosestPathForLocation(x, y);
  1375.         return null;
  1376.     }
  1377.  
  1378.     /**
  1379.      * Returns the row to the node that is closest to x,y.  If
  1380.      * nothing is visible or there is no model, returns -1. Otherwise,
  1381.      * it always returns a valid row.  To test if the returned object is 
  1382.      * exactly at x, y, get the bounds for the node at the returned
  1383.      * row and test x, y against that.
  1384.      *
  1385.      * @param x an int giving the number of pixels horizontally from
  1386.      *          the left edge of the display area, minus any left margin
  1387.      * @param y an int giving the number of pixels vertically from
  1388.      *          the top of the display area, minus any top margin
  1389.      * @return the row closest to the location, -1 if nothing is
  1390.      *         visible or there is no model
  1391.      *
  1392.      * @see #getRowForLocation
  1393.      * @see #getRowBounds
  1394.      */
  1395.     public int getClosestRowForLocation(int x, int y) {
  1396.         TreeUI                  tree = getUI();
  1397.  
  1398.         if(tree != null)
  1399.             return tree.getClosestRowForLocation(x, y);
  1400.         return -1;
  1401.     }
  1402.  
  1403.     /**
  1404.      * Returns true if the tree is being edited.  The item that is being
  1405.      * edited can be obtained using <code>getSelectionPath</code>.
  1406.      *
  1407.      * @return true if the user is currently editing a node
  1408.      * @see #getSelectionPath
  1409.      */
  1410.     public boolean isEditing() {
  1411.         TreeUI                  tree = getUI();
  1412.  
  1413.         if(tree != null)
  1414.             return tree.isEditing();
  1415.         return false;
  1416.     }
  1417.  
  1418.     /**
  1419.      * Stops the current editing session.  Has no effect if the
  1420.      * tree isn't being edited.
  1421.      *
  1422.      * @return true if editing was in progress and is now stopped,
  1423.      *              false if editing was not in progress
  1424.      */
  1425.     public boolean stopEditing() {
  1426.         TreeUI                  tree = getUI();
  1427.  
  1428.         if(tree != null)
  1429.             return tree.stopEditing();
  1430.         return false;
  1431.     }
  1432.  
  1433.     /**
  1434.      * Selects the node identified by the specified path and initiates
  1435.      * editing.  The edit-attempt fails if the CellEditor does not allow
  1436.      * editing for the specified item.
  1437.      * 
  1438.      * @param path  the TreePath identifying a node
  1439.      */
  1440.     public void startEditingAtPath(TreePath path) {
  1441.         TreeUI                  tree = getUI();
  1442.  
  1443.         if(tree != null)
  1444.             tree.startEditingAtPath(path);
  1445.     }
  1446.  
  1447.     /**
  1448.      * Returns the path to the element that is currently being edited.
  1449.      *
  1450.      * @return  the TreePath for the node being edited
  1451.      */
  1452.     public TreePath getEditingPath() {
  1453.         TreeUI                  tree = getUI();
  1454.  
  1455.         if(tree != null)
  1456.             return tree.getEditingPath();
  1457.         return null;
  1458.     }
  1459.  
  1460.     //
  1461.     // Following are primarily convenience methods for mapping from
  1462.     // row based selections to path selections.  Sometimes it is
  1463.     // easier to deal with these than paths (mouse downs, key downs
  1464.     // usually just deal with index based selections).
  1465.     // Since row based selections require a UI many of these won't work
  1466.     // without one.
  1467.     //
  1468.  
  1469.     /**
  1470.      * Sets the tree's selection model. When a null value is specified
  1471.      * an empty electionModel is used, which does not allow selections.
  1472.      *
  1473.      * @param selectionModel the TreeSelectionModel to use, or null to
  1474.      *        disable selections
  1475.      * @see TreeSelectionModel
  1476.      * @beaninfo
  1477.      *        bound: true
  1478.      *  description: The tree's selection model.
  1479.      */
  1480.     public void setSelectionModel(TreeSelectionModel selectionModel) {
  1481.         if(selectionModel == null)
  1482.             selectionModel = EmptySelectionModel.sharedInstance();
  1483.  
  1484.         TreeSelectionModel         oldValue = this.selectionModel;
  1485.  
  1486.         this.selectionModel = selectionModel;
  1487.         firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue,
  1488.                            this.selectionModel);
  1489.         if (accessibleContext != null) {
  1490.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1491.         }
  1492.     }
  1493.  
  1494.     /**
  1495.      * Returns the model for selections. This should always return a 
  1496.      * non-null value. If you don't want to allow anything to be selected
  1497.      * set the selection model to null, which forces an empty
  1498.      * selection model to be used.
  1499.      *
  1500.      * @param the TreeSelectionModel in use
  1501.      * @see #setSelectionModel
  1502.      */
  1503.     public TreeSelectionModel getSelectionModel() {
  1504.         return selectionModel;
  1505.     }
  1506.  
  1507.     /**
  1508.      * Returns JTreePath instances representing the path between index0
  1509.      * and index1 (including index1).  Returns null if there is no tree.
  1510.      *
  1511.      * @param index0  an int specifying a display row, where 0 is the
  1512.      *                first row in the display
  1513.      * @param index0  an int specifying a second display row
  1514.      * @return an array of TreePath objects, one for each node between
  1515.      *         index0 and index1, inclusive
  1516.      */
  1517.     protected TreePath[] getPathBetweenRows(int index0, int index1) {
  1518.         int              newMinIndex, newMaxIndex;
  1519.         TreeUI           tree = getUI();
  1520.  
  1521.         newMinIndex = Math.min(index0, index1);
  1522.         newMaxIndex = Math.max(index0, index1);
  1523.  
  1524.         if(tree != null) {
  1525.             TreePath[]            selection = new TreePath[newMaxIndex -
  1526.                                                             newMinIndex + 1];
  1527.  
  1528.             for(int counter = newMinIndex; counter <= newMaxIndex; counter++)
  1529.                 selection[counter - newMinIndex] = tree.getPathForRow(counter);
  1530.             return selection;
  1531.         }
  1532.         return null;
  1533.     }
  1534.  
  1535.     /**
  1536.      * Selects the nodes between index0 and index1, inclusive.
  1537.      *
  1538.      * @param index0  an int specifying a display row, where 0 is the
  1539.      *                first row in the display
  1540.      * @param index0  an int specifying a second display row
  1541.     */
  1542.     public void setSelectionInterval(int index0, int index1) {
  1543.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1544.  
  1545.         this.getSelectionModel().setSelectionPaths(paths);
  1546.         if (accessibleContext != null) {
  1547.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1548.         }
  1549.     }
  1550.  
  1551.     /**
  1552.      * Adds the paths between index0 and index1, inclusive, to the 
  1553.      * selection.
  1554.      *
  1555.      * @param index0  an int specifying a display row, where 0 is the
  1556.      *                first row in the display
  1557.      * @param index0  an int specifying a second display row
  1558.      */
  1559.     public void addSelectionInterval(int index0, int index1) {
  1560.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1561.  
  1562.         this.getSelectionModel().addSelectionPaths(paths);
  1563.         if (accessibleContext != null) {
  1564.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1565.         }
  1566.     }
  1567.  
  1568.     /**
  1569.      * Removes the nodes between index0 and index1, inclusive, from the 
  1570.      * selection.
  1571.      *
  1572.      * @param index0  an int specifying a display row, where 0 is the
  1573.      *                first row in the display
  1574.      * @param index0  an int specifying a second display row
  1575.      */
  1576.     public void removeSelectionInterval(int index0, int index1) {
  1577.         TreePath[]         paths = getPathBetweenRows(index0, index1);
  1578.  
  1579.         this.getSelectionModel().removeSelectionPaths(paths);
  1580.         if (accessibleContext != null) {
  1581.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1582.         }
  1583.     }
  1584.  
  1585.     /**
  1586.      * Removes the node identified by the specified path from the current
  1587.      * selection.
  1588.      * 
  1589.      * @param path  the TreePath identifying a node
  1590.      */
  1591.     public void removeSelectionPath(TreePath path) {
  1592.         this.getSelectionModel().removeSelectionPath(path);
  1593.         if (accessibleContext != null) {
  1594.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1595.         }
  1596.     }
  1597.  
  1598.     /**
  1599.      * Removes the nodes identified by the specified paths from the 
  1600.      * current selection.
  1601.      *
  1602.      * @param paths an array of TreePath objects that specifies the nodes
  1603.      *              to remove
  1604.      */
  1605.     public void removeSelectionPaths(TreePath[] paths) {
  1606.         this.getSelectionModel().removeSelectionPaths(paths);
  1607.         if (accessibleContext != null) {
  1608.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1609.         }
  1610.     }
  1611.  
  1612.     /**
  1613.      * Removes the path at the index <code>row</code> from the current
  1614.      * selection.
  1615.      * 
  1616.      * @param path  the TreePath identifying the node to remove
  1617.      */
  1618.     public void removeSelectionRow(int row) {
  1619.         int[]             rows = { row };
  1620.  
  1621.         removeSelectionRows(rows);
  1622.     }
  1623.  
  1624.     /**
  1625.      * Removes the paths that are selected at each of the specified
  1626.      * rows.
  1627.      *
  1628.      * @param row  an array of ints specifying display rows, where 0 is 
  1629.      *             the first row in the display
  1630.      */
  1631.     public void removeSelectionRows(int[] rows) {
  1632.         TreeUI             ui = getUI();
  1633.  
  1634.         if(ui != null && rows != null) {
  1635.             int                  numRows = rows.length;
  1636.             TreePath[]           paths = new TreePath[numRows];
  1637.  
  1638.             for(int counter = 0; counter < numRows; counter++)
  1639.                 paths[counter] = ui.getPathForRow(rows[counter]);
  1640.             removeSelectionPaths(paths);
  1641.         }
  1642.     }
  1643.  
  1644.     /**
  1645.      * Clears the selection.
  1646.      */
  1647.     public void clearSelection() {
  1648.         getSelectionModel().clearSelection();
  1649.         if (accessibleContext != null) {
  1650.             ((AccessibleJTree)accessibleContext).fireSelectionPropertyChange();
  1651.         }
  1652.     }
  1653.  
  1654.     /**
  1655.      * Returns true if the selection is currently empty.
  1656.      *
  1657.      * @return true if the selection is currently empty
  1658.      */
  1659.     public boolean isSelectionEmpty() {
  1660.         return getSelectionModel().isSelectionEmpty();
  1661.     }
  1662.  
  1663.     /**
  1664.      * Adds a listener for TreeExpansion events.
  1665.      *
  1666.      * @param tel a TreeExpansionListener that will be notified when
  1667.      *            a tree node is expanded or collapsed (a "negative
  1668.      *            expansion")
  1669.      */
  1670.     public void addTreeExpansionListener(TreeExpansionListener tel) {
  1671.         listenerList.add(TreeExpansionListener.class, tel);
  1672.     }
  1673.  
  1674.     /**
  1675.      * Removes a listener for TreeExpansion events.
  1676.      *
  1677.      * @param tel the TreeExpansionListener to remove
  1678.      */
  1679.     public void removeTreeExpansionListener(TreeExpansionListener tel) {
  1680.         listenerList.remove(TreeExpansionListener.class, tel);
  1681.     }
  1682.  
  1683.     /**
  1684.      * Notify all listeners that have registered interest for
  1685.      * notification on this event type.  The event instance 
  1686.      * is lazily created using the parameters passed into 
  1687.      * the fire method.
  1688.      *
  1689.      * @param path the TreePath indicating the node that was expanded
  1690.      * @see EventListenerList
  1691.      */
  1692.      public void fireTreeExpanded(TreePath path) {
  1693.         // Guaranteed to return a non-null array
  1694.         Object[] listeners = listenerList.getListenerList();
  1695.         TreeExpansionEvent e = null;
  1696.         // Process the listeners last to first, notifying
  1697.         // those that are interested in this event
  1698.         for (int i = listeners.length-2; i>=0; i-=2) {
  1699.             if (listeners[i]==TreeExpansionListener.class) {
  1700.                 // Lazily create the event:
  1701.                 if (e == null)
  1702.                     e = new TreeExpansionEvent(this, path);
  1703.                 ((TreeExpansionListener)listeners[i+1]).
  1704.                     treeExpanded(e);
  1705.             }          
  1706.         }
  1707.     }   
  1708.  
  1709.     /**
  1710.      * Notify all listeners that have registered interest for
  1711.      * notification on this event type.  The event instance 
  1712.      * is lazily created using the parameters passed into 
  1713.      * the fire method.
  1714.      *
  1715.      * @param path the TreePath indicating the node that was collapsed
  1716.      * @see EventListenerList
  1717.      */
  1718.     public void fireTreeCollapsed(TreePath path) {
  1719.         // Guaranteed to return a non-null array
  1720.         Object[] listeners = listenerList.getListenerList();
  1721.         TreeExpansionEvent e = null;
  1722.         // Process the listeners last to first, notifying
  1723.         // those that are interested in this event
  1724.         for (int i = listeners.length-2; i>=0; i-=2) {
  1725.             if (listeners[i]==TreeExpansionListener.class) {
  1726.                 // Lazily create the event:
  1727.                 if (e == null)
  1728.                     e = new TreeExpansionEvent(this, path);
  1729.                 ((TreeExpansionListener)listeners[i+1]).
  1730.                     treeCollapsed(e);
  1731.             }          
  1732.         }
  1733.     }   
  1734.  
  1735.     /**
  1736.      * Adds a listener for TreeSelection events.
  1737.      *
  1738.      * @param tsl the TreeSelectionListener that will be notified when
  1739.      *            a node is selected or deselected (a "negative
  1740.      *            selection")
  1741.      */
  1742.     public void addTreeSelectionListener(TreeSelectionListener tsl) {
  1743.         listenerList.add(TreeSelectionListener.class,tsl);
  1744.         if(listenerList.getListenerCount(TreeSelectionListener.class) != 0
  1745.            && selectionRedirector == null) {
  1746.             selectionRedirector = new TreeSelectionRedirector();
  1747.             selectionModel.addTreeSelectionListener(selectionRedirector);
  1748.         }
  1749.     }
  1750.  
  1751.     /**
  1752.      * Removes a TreeSelection listener.
  1753.      *
  1754.      * @param tsl the TreeSelectionListener to remove
  1755.      */
  1756.     public void removeTreeSelectionListener(TreeSelectionListener tsl) {
  1757.         listenerList.remove(TreeSelectionListener.class,tsl);
  1758.         if(listenerList.getListenerCount(TreeSelectionListener.class) == 0
  1759.            && selectionRedirector != null) {
  1760.             selectionModel.removeTreeSelectionListener
  1761.                 (selectionRedirector);
  1762.             selectionRedirector = null;
  1763.         }
  1764.     }
  1765.  
  1766.     /**
  1767.      * Notify all listeners that have registered interest for
  1768.      * notification on this event type.  The event instance 
  1769.      * is lazily created using the parameters passed into 
  1770.      * the fire method.
  1771.      *
  1772.      * @param e the TreeSelectionEvent generated by the TreeSelectionModel
  1773.      *          when a node is selected or deselected
  1774.      * @see EventListenerList
  1775.      */
  1776.     protected void fireValueChanged(TreeSelectionEvent e) {
  1777.         // Guaranteed to return a non-null array
  1778.         Object[] listeners = listenerList.getListenerList();
  1779.         // Process the listeners last to first, notifying
  1780.         // those that are interested in this event
  1781.         for (int i = listeners.length-2; i>=0; i-=2) {
  1782.             // TreeSelectionEvent e = null;
  1783.             if (listeners[i]==TreeSelectionListener.class) {
  1784.                 // Lazily create the event:
  1785.                 // if (e == null)
  1786.                 // e = new ListSelectionEvent(this, firstIndex, lastIndex);
  1787.                 ((TreeSelectionListener)listeners[i+1]).valueChanged(e);
  1788.             }          
  1789.         }
  1790.     }
  1791.  
  1792.     /**
  1793.      * Sent when the tree has changed enough that we need to resize
  1794.      * the bounds, but not enough that we need to remove the
  1795.      * expanded node set (e.g nodes were expanded or collapsed, or
  1796.      * nodes were inserted into the tree)
  1797.      */
  1798.     public void treeDidChange() {
  1799.         revalidate();
  1800.         repaint();
  1801.     }
  1802.  
  1803.     /**
  1804.      * Sets the number of rows that are to be visible.
  1805.      * This will only work if the reciever is contained in a JScrollPane,
  1806.      * and will adjust the preferred size and size of that scrollpane.
  1807.      *
  1808.      * @param newCount the number of rows to display
  1809.      * @beaninfo
  1810.      *        bound: true
  1811.      *  description: The number of rows that are to be visible.
  1812.      */
  1813.     public void setVisibleRowCount(int newCount) {
  1814.         int                 oldCount = visibleRowCount;
  1815.  
  1816.         visibleRowCount = newCount;
  1817.         firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldCount,
  1818.                            visibleRowCount);
  1819.         invalidate();
  1820.         if (accessibleContext != null) {
  1821.             ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1822.         }
  1823.     }
  1824.  
  1825.     /**
  1826.      * Returns the number of rows that are visible in the display area.
  1827.      *
  1828.      * @return the number of rows displayed
  1829.      */
  1830.     public int getVisibleRowCount() {
  1831.         return visibleRowCount;
  1832.     }
  1833.  
  1834.     // Serialization support.  
  1835.     private void writeObject(ObjectOutputStream s) throws IOException {
  1836.         Vector      values = new Vector();
  1837.  
  1838.         s.defaultWriteObject();
  1839.         // Save the cellRenderer, if its Serializable.
  1840.         if(cellRenderer != null && cellRenderer instanceof Serializable) {
  1841.             values.addElement("cellRenderer");
  1842.             values.addElement(cellRenderer);
  1843.         }
  1844.         // Save the cellEditor, if its Serializable.
  1845.         if(cellEditor != null && cellEditor instanceof Serializable) {
  1846.             values.addElement("cellEditor");
  1847.             values.addElement(cellEditor);
  1848.         }
  1849.         // Save the treeModel, if its Serializable.
  1850.         if(treeModel != null && treeModel instanceof Serializable) {
  1851.             values.addElement("treeModel");
  1852.             values.addElement(treeModel);
  1853.         }
  1854.         // Save the selectionModel, if its Serializable.
  1855.         if(selectionModel != null && selectionModel instanceof Serializable) {
  1856.             values.addElement("selectionModel");
  1857.             values.addElement(selectionModel);
  1858.         }
  1859.         s.writeObject(values);
  1860.     }
  1861.  
  1862.     private void readObject(ObjectInputStream s) 
  1863.         throws IOException, ClassNotFoundException {
  1864.         s.defaultReadObject();
  1865.  
  1866.         Vector          values = (Vector)s.readObject();
  1867.         int             indexCounter = 0;
  1868.         int             maxCounter = values.size();
  1869.  
  1870.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1871.            equals("cellRenderer")) {
  1872.             cellRenderer = (TreeCellRenderer)values.elementAt(++indexCounter);
  1873.             indexCounter++;
  1874.         }
  1875.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1876.            equals("cellEditor")) {
  1877.             cellEditor = (TreeCellEditor)values.elementAt(++indexCounter);
  1878.             indexCounter++;
  1879.         }
  1880.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1881.            equals("treeModel")) {
  1882.             treeModel = (TreeModel)values.elementAt(++indexCounter);
  1883.             indexCounter++;
  1884.         }
  1885.         if(indexCounter < maxCounter && values.elementAt(indexCounter).
  1886.            equals("selectionModel")) {
  1887.             selectionModel = (TreeSelectionModel)values.elementAt(++indexCounter);
  1888.             indexCounter++;
  1889.         }
  1890.     }
  1891.  
  1892.     /**
  1893.      * EmptySelectionModel is a TreeSelectionModel that does not allow
  1894.      * anything to be selected.
  1895.      * <p>
  1896.      * Warning: serialized objects of this class will not be compatible with
  1897.      * future swing releases.  The current serialization support is appropriate
  1898.      * for short term storage or RMI between Swing1.0 applications.  It will
  1899.      * not be possible to load serialized Swing1.0 objects with future releases
  1900.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1901.      * baseline for the serialized form of Swing objects.
  1902.      */
  1903.     protected static class EmptySelectionModel extends
  1904.               DefaultTreeSelectionModel
  1905.     {
  1906.         /** Unique shared instance. */
  1907.         protected static final EmptySelectionModel sharedInstance =
  1908.             new EmptySelectionModel();
  1909.  
  1910.         /** Returns a shared instance of an empty selection model */
  1911.         static public EmptySelectionModel sharedInstance() {
  1912.             return sharedInstance;
  1913.         }
  1914.  
  1915.         /** A null implementation that selects nothing */
  1916.         public void setSelectionPaths(TreePath[] pPaths) {}
  1917.         /** A null implementation that adds nothing */
  1918.         public void addSelectionPaths(TreePath[] paths) {}
  1919.         /** A null implementation that removes nothing */
  1920.         public void removeSelectionPaths(TreePath[] paths) {}
  1921.     }
  1922.  
  1923.  
  1924.     /**
  1925.      * Handles creating a new TreeSelectionEvent with the JTree as the
  1926.      * source and passing it off to all the listeners.
  1927.      * <p>
  1928.      * Warning: serialized objects of this class will not be compatible with
  1929.      * future swing releases.  The current serialization support is appropriate
  1930.      * for short term storage or RMI between Swing1.0 applications.  It will
  1931.      * not be possible to load serialized Swing1.0 objects with future releases
  1932.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1933.      * baseline for the serialized form of Swing objects.
  1934.      */
  1935.     protected class TreeSelectionRedirector implements Serializable,
  1936.                     TreeSelectionListener
  1937.     {
  1938.         /**
  1939.          * Invoked by the TreeSelectionModel when the selection changes.
  1940.          * 
  1941.          * @param e the TreeSelectionEvent generated by the TreeSelectionModel
  1942.          */
  1943.         public void valueChanged(TreeSelectionEvent e) {
  1944.             TreeSelectionEvent       newE;
  1945.  
  1946.             newE = (TreeSelectionEvent)e.cloneWithSource(JTree.this);
  1947.             fireValueChanged(newE);
  1948.         }
  1949.     } // End of class JTree.TreeSelectionRedirector
  1950.  
  1951.     /**
  1952.      * Returns true to indicate that this component paints every pixel
  1953.      * in its range. (In other words, it does not have a transparent
  1954.      * background or foreground.)
  1955.      *
  1956.      * @return true
  1957.      * @see JComponent#isOpaque
  1958.      */
  1959.     public boolean isOpaque() {
  1960.         return true;
  1961.     }
  1962.  
  1963.     //
  1964.     // Scrollable interface
  1965.     //
  1966.  
  1967.     /**
  1968.      * Returns the preferred viewable size of a JTree. The height is
  1969.      * determined from <code>getVisibleRowCount</code> and the width
  1970.      * is the current preferred width.
  1971.      *
  1972.      * @return a Dimension object containing the preferred size
  1973.      */
  1974.     public Dimension getPreferredScrollableViewportSize() {
  1975.         int                 width = getPreferredSize().width;
  1976.         int                 visRows = getVisibleRowCount();
  1977.         int                 height;
  1978.  
  1979.         if(isFixedRowHeight())
  1980.             height = visRows * getRowHeight();
  1981.         else {
  1982.             TreeUI          ui = getUI();
  1983.  
  1984.             if(ui != null && ui.getRowCount() > 0)
  1985.                 height = getRowBounds(0).height * visRows;
  1986.             else
  1987.                 height = 16 * visRows;
  1988.         }
  1989.         return new Dimension(width, height);
  1990.     }
  1991.  
  1992.     /**
  1993.      * Returns the amount to increment when scrolling. The amount is
  1994.      * the height of the first visible row that isn't completely in view
  1995.      * or, if it is totally visible, the height of the next row in the
  1996.      * scrolling direction.
  1997.      * 
  1998.      * @param visibleRect The view area visible within the viewport
  1999.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2000.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2001.      * @return The "unit" increment for scrolling in the specified direction
  2002.      * @see JScrollBar#setUnitIncrement
  2003.      */
  2004.     public int getScrollableUnitIncrement(Rectangle visibleRect,
  2005.                                           int orientation, int direction) {
  2006.         if(orientation == SwingConstants.VERTICAL) {
  2007.             Rectangle       rowBounds;
  2008.             int             firstIndex = getClosestRowForLocation
  2009.                                          (0, visibleRect.y);
  2010.  
  2011.             if(firstIndex != -1) {
  2012.                 rowBounds = getRowBounds(firstIndex);
  2013.                 if(rowBounds.y != visibleRect.y) {
  2014.                     if(direction < 0) // UP
  2015.                         return (visibleRect.y - rowBounds.y);
  2016.                     return (rowBounds.y + rowBounds.height - visibleRect.y);
  2017.                 }
  2018.                 if(direction < 0) { // UP
  2019.                     if(firstIndex != 0) {
  2020.                         rowBounds = getRowBounds(firstIndex - 1);
  2021.                         return rowBounds.height;
  2022.                     }
  2023.                 }
  2024.                 else {
  2025.                     return rowBounds.height;
  2026.                 }
  2027.             }
  2028.             return 0;
  2029.         }
  2030.         return 4;
  2031.     }
  2032.  
  2033.  
  2034.     /**
  2035.      * Returns the amount for a block inrecment, which is the height or
  2036.      * width of <code>visibleRect</code>, based on <code>orientation</code>.
  2037.      * 
  2038.      * @param visibleRect The view area visible within the viewport
  2039.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  2040.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  2041.      * @return The "block" increment for scrolling in the specified direction.
  2042.      * @see JScrollBar#setBlockIncrement
  2043.      */
  2044.     public int getScrollableBlockIncrement(Rectangle visibleRect,
  2045.                                            int orientation, int direction) {
  2046.         return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
  2047.             visibleRect.width;
  2048.     }
  2049.     
  2050.  
  2051.     /**
  2052.      * Returns false to indicate that the width of the viewport does not 
  2053.      * determine the width of the table.
  2054.      * 
  2055.      * @return false
  2056.      * @see Scrollable#getScrollableTracksViewportWidth
  2057.      */
  2058.     public boolean getScrollableTracksViewportWidth() {
  2059.         return false;
  2060.     }
  2061.  
  2062.     /**
  2063.      * Returns false to indicate that the height of the viewport does not 
  2064.      * determine the height of the table.
  2065.      * 
  2066.      * @return false
  2067.      * @see Scrollable#getScrollableTracksViewportHeight
  2068.      */
  2069.     public boolean getScrollableTracksViewportHeight() {
  2070.         return false;
  2071.     }
  2072.  
  2073.     /**
  2074.      * DynamicUtilTreeNode can wrap vectors/hashtables/arrays/strings and
  2075.      * create the appropriate children tree nodes as necessary. It is
  2076.      * dynamic in that it'll only create the children as necessary.
  2077.      * <p>
  2078.      * Warning: serialized objects of this class will not be compatible with
  2079.      * future swing releases.  The current serialization support is appropriate
  2080.      * for short term storage or RMI between Swing1.0 applications.  It will
  2081.      * not be possible to load serialized Swing1.0 objects with future releases
  2082.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  2083.      * baseline for the serialized form of Swing objects.
  2084.      */
  2085.     public static class DynamicUtilTreeNode extends DefaultMutableTreeNode {
  2086.         /* Does the receiver have children? */
  2087.         protected boolean            hasChildren;
  2088.         /** Value to create children with. */
  2089.         protected Object             childValue;
  2090.         /* Have the children been loaded yet? */
  2091.         protected boolean            loadedChildren;
  2092.  
  2093.         /**
  2094.          * Adds to parent all the children in <code>children</code>.
  2095.          * If <code>children</code> is an array or Vector all of its
  2096.          * elements are added is children, otherwise if <code>children</code>
  2097.          * is a Hashtable all the key/value pairs are added in the order
  2098.          * Enumeration returns them.
  2099.          */
  2100.         public static void createChildren(DefaultMutableTreeNode parent,
  2101.                                           Object children) {
  2102.             if(children instanceof Vector) {
  2103.                 Vector          childVector = (Vector)children;
  2104.  
  2105.                 for(int counter = 0, maxCounter = childVector.size();
  2106.                     counter < maxCounter; counter++)
  2107.                     parent.add(new DynamicUtilTreeNode
  2108.                                (childVector.elementAt(counter),
  2109.                                 childVector.elementAt(counter)));
  2110.             }
  2111.             else if(children instanceof Hashtable) {
  2112.                 Hashtable           childHT = (Hashtable)children;
  2113.                 Enumeration         keys = childHT.keys();
  2114.                 Object              aKey;
  2115.  
  2116.                 while(keys.hasMoreElements()) {
  2117.                     aKey = keys.nextElement();
  2118.                     parent.add(new DynamicUtilTreeNode(aKey,
  2119.                                                        childHT.get(aKey)));
  2120.                 }
  2121.             }
  2122.             else if(children instanceof Object[]) {
  2123.                 Object[]             childArray = (Object[])children;
  2124.  
  2125.                 for(int counter = 0, maxCounter = childArray.length;
  2126.                     counter < maxCounter; counter++)
  2127.                     parent.add(new DynamicUtilTreeNode(childArray[counter],
  2128.                                                        childArray[counter]));
  2129.             }
  2130.         }
  2131.  
  2132.         /**
  2133.          * Creates a node with the specified object as its value and
  2134.          * with the specified children. For the node to allow children,
  2135.          * the children-object must be an array of objects, a Vector,
  2136.          * or a Hashtable -- even if empty. Otherwise, the node is not
  2137.          * allowed to have children.
  2138.          *
  2139.          * @param value  the Object that is the value for the new node
  2140.          * @param children an array of Objects, a Vector, or a Hashtable
  2141.          *                 used to create the child nodes. If any other
  2142.          *                 object is specified, or if the value is null,
  2143.          *                 then the node is not allowed to have children.
  2144.          */
  2145.         public DynamicUtilTreeNode(Object value, Object children) {
  2146.             super(value);
  2147.             loadedChildren = false;
  2148.             childValue = children;
  2149.             if(children != null) {
  2150.                 if(children instanceof Vector)
  2151.                     setAllowsChildren(true);
  2152.                 else if(children instanceof Hashtable)
  2153.                     setAllowsChildren(true);
  2154.                 else if(children instanceof Object[])
  2155.                     setAllowsChildren(true);
  2156.                 else
  2157.                     setAllowsChildren(false);
  2158.             }
  2159.             else
  2160.                 setAllowsChildren(false);
  2161.         }
  2162.  
  2163.         /**
  2164.          * Returns true if this node allows children. Whether the node
  2165.          * allows children depends on how it was created.
  2166.          *
  2167.          * @return true if this node allows children, false otherwise.
  2168.          * @see #DynamicUtilTreeNode(Object, Object)
  2169.          */
  2170.         public boolean isLeaf() {
  2171.             return !getAllowsChildren();
  2172.         }
  2173.  
  2174.         /**
  2175.          * Returns the number of child nodes.
  2176.          *
  2177.          * @return the number of child nodes
  2178.          */
  2179.         public int getChildCount() {
  2180.             if(!loadedChildren)
  2181.                 loadChildren();
  2182.             return super.getChildCount();
  2183.         }
  2184.  
  2185.         /**
  2186.          * Loads the children based on childValue. If childValue is
  2187.          * a Vector orarray each element  added as a child, if childValue
  2188.          * is a Hashtable each key/value pair is added in the order that
  2189.          * Enumeration returns the keys.
  2190.          */
  2191.         protected void loadChildren() {
  2192.             loadedChildren = true;
  2193.             createChildren(this, childValue);
  2194.         }
  2195.     }
  2196.  
  2197. /////////////////
  2198. // Accessibility support
  2199. ////////////////
  2200.  
  2201.     /**
  2202.      * Get the AccessibleContext associated with this JComponent
  2203.      *
  2204.      * @return the AccessibleContext of this JComponent
  2205.      */
  2206.     public AccessibleContext getAccessibleContext() {
  2207.         if (accessibleContext == null) {
  2208.             accessibleContext = new AccessibleJTree();
  2209.         }
  2210.         return accessibleContext;
  2211.     }
  2212.  
  2213.     //
  2214.     // *** should also implement AccessibleAction (expansion/contraction)
  2215.     // *** and what's up with keyboard navigation/manipulation?
  2216.     //
  2217.     /**
  2218.      * The class used to obtain the accessible role for this object.
  2219.      * <p>
  2220.      * Warning: serialized objects of this class will not be compatible with
  2221.      * future swing releases.  The current serialization support is appropriate
  2222.      * for short term storage or RMI between Swing1.0 applications.  It will
  2223.      * not be possible to load serialized Swing1.0 objects with future releases
  2224.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  2225.      * baseline for the serialized form of Swing objects.
  2226.      */
  2227.     protected class AccessibleJTree extends AccessibleJComponent 
  2228.     implements AccessibleSelection, TreeModelListener, TreeExpansionListener  {
  2229.  
  2230.         public AccessibleJTree() {
  2231.            // Add a tree model listener for JTree
  2232.            JTree.this.getModel().addTreeModelListener(this);
  2233.            JTree.this.addTreeExpansionListener(this);      
  2234.         } 
  2235.  
  2236.         /**
  2237.          * Fire a visible data property change notification.
  2238.          *
  2239.          */
  2240.         public void fireVisibleDataPropertyChange() {
  2241.            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  2242.                               new Boolean(false), new Boolean(true));
  2243.         }
  2244.  
  2245.         /**
  2246.          * Fire a selection property change notification.
  2247.          *
  2248.          */
  2249.         public void fireSelectionPropertyChange() {
  2250.            fireVisibleDataPropertyChange();
  2251.            firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
  2252.                               new Boolean(false), new Boolean(true));
  2253.         }
  2254.  
  2255.  
  2256.         // Fire the visible data changes for the model changes.
  2257.  
  2258.         /**
  2259.          * Tree Model Node change notification.
  2260.          *
  2261.          * @param e  a Tree Model event
  2262.          */
  2263.         public void treeNodesChanged(TreeModelEvent e) {
  2264.            fireVisibleDataPropertyChange();
  2265.         }
  2266.  
  2267.         /**
  2268.          * Tree Model Node change notification.
  2269.          *
  2270.          * @param e  a Tree node insertion event
  2271.          */
  2272.         public void treeNodesInserted(TreeModelEvent e) {
  2273.            fireVisibleDataPropertyChange();
  2274.         }
  2275.  
  2276.         /**
  2277.          * Tree Model Node change notification.
  2278.          *
  2279.          * @param e  a Tree node(s) removal event
  2280.          */
  2281.         public  void treeNodesRemoved(TreeModelEvent e) {
  2282.            fireVisibleDataPropertyChange();
  2283.         }
  2284.  
  2285.         /**
  2286.          * Tree Model structure change change notification.
  2287.          *
  2288.          * @param e  a Tree Model event
  2289.          */
  2290.         public  void treeStructureChanged(TreeModelEvent e) {
  2291.            fireVisibleDataPropertyChange();
  2292.         }
  2293.  
  2294.         /**
  2295.          * Tree Collapsed notification.
  2296.          *
  2297.          * @param e  a TreeExpansionEvent
  2298.          */
  2299.         public  void treeCollapsed(TreeExpansionEvent e) {
  2300.            fireVisibleDataPropertyChange();
  2301.         }
  2302.  
  2303.         /**
  2304.          * Tree Model Expansion notification.
  2305.          *
  2306.          * @param e  a Tree node insertion event
  2307.          */
  2308.         public  void treeExpanded(TreeExpansionEvent e) {
  2309.             fireVisibleDataPropertyChange();
  2310.          }
  2311.  
  2312.  
  2313.         private AccessibleContext getCurrentAccessibleContext() {
  2314.             Component c = getCurrentComponent();
  2315.             if (c instanceof Accessible) {
  2316.                 return (((Accessible) c).getAccessibleContext());
  2317.             } else {
  2318.                 return null;
  2319.             }
  2320.         }
  2321.  
  2322.         private Component getCurrentComponent() {
  2323.             // is the object visible?
  2324.             // if so, get row, selected, focus & leaf state, 
  2325.             // and then get the renderer component and return it
  2326.             TreeModel model = JTree.this.getModel();
  2327.             TreePath path = new TreePath(model.getRoot());
  2328.             if (JTree.this.isVisible(path)) {
  2329.                 TreeCellRenderer r = JTree.this.getCellRenderer();
  2330.                 TreeUI ui = JTree.this.getUI();
  2331.                 if (ui != null) {
  2332.                     int row = ui.getRowForPath(path);
  2333.                     boolean selected = JTree.this.isPathSelected(path);
  2334.                     boolean expanded = JTree.this.isExpanded(path);
  2335.                     boolean hasFocus = false; // how to tell?? -PK
  2336.                     return r.getTreeCellRendererComponent(JTree.this, 
  2337.                         model.getRoot(), selected, expanded, 
  2338.                         model.isLeaf(model.getRoot()), row, hasFocus);
  2339.                 }
  2340.             } 
  2341.             return null;
  2342.         }
  2343.  
  2344.         // Overridden methods from AccessibleJComponent
  2345.  
  2346.         /**
  2347.          * Get the Accessible name of this JTree.  This returns the name
  2348.          * of the top-most node in the tree
  2349.          *
  2350.          * @return the Accessible name of this JTree
  2351.          */
  2352.         public String getAccessibleName() {
  2353.             AccessibleContext ac = getCurrentAccessibleContext();
  2354.             if (ac != null) {
  2355.                 String name = ac.getAccessibleName();
  2356.                 if ((name != null) && (name != "")) {
  2357.                     return ac.getAccessibleName();
  2358.                 } else {
  2359.                     return null;
  2360.                 }
  2361.             }
  2362.             if ((accessibleName != null) && (accessibleName != "")) {
  2363.                 return accessibleName;
  2364.             } else {
  2365.                 return null;
  2366.             }
  2367.         }
  2368.  
  2369.         //
  2370.         // *** should check toolip text for desc. (needs MouseEvent)
  2371.         //
  2372.         public String getAccessibleDescription() {
  2373.             AccessibleContext ac = getCurrentAccessibleContext();
  2374.             if (ac != null) {
  2375.                 return ac.getAccessibleDescription();
  2376.             } else {
  2377.                 return super.getAccessibleDescription();
  2378.             }
  2379.         }
  2380.  
  2381.         /**
  2382.          * Get the role of this object.
  2383.          *
  2384.          * @return an instance of AccessibleRole describing the role of the 
  2385.          * object
  2386.          * @see AccessibleRole
  2387.          */
  2388.         public AccessibleRole getAccessibleRole() {
  2389.             return AccessibleRole.TREE;
  2390.         }
  2391.  
  2392.         /**
  2393.          * Returns the Accessible child, if one exists, contained at the local
  2394.          * coordinate Point.
  2395.          *
  2396.          * @param p point in local coordinates of the this Accessible
  2397.          * @return the Accessible, if it exists, at the specified location;
  2398.          * else null
  2399.          */
  2400.         public Accessible getAccessibleAt(Point p) {
  2401.             TreePath path = getClosestPathForLocation(p.x, p.y);
  2402.             if (path != null) {
  2403.                 return new AccessibleJTreeNode(JTree.this, path, JTree.this);
  2404.             } else {
  2405.                 return null;
  2406.             }
  2407.         }
  2408.  
  2409.         /**
  2410.          * Returns the number of top-level children nodes of this 
  2411.          * JTree.  Each of these nodes may in turn have children nodes.
  2412.          *
  2413.          * @return the number of accessible children nodes in the tree.
  2414.          */
  2415.         public int getAccessibleChildrenCount() {
  2416.             TreeModel model = JTree.this.getModel();
  2417.             if (model != null) {
  2418.                 return model.getChildCount(model.getRoot());
  2419.             } else {
  2420.                 return 0;
  2421.             }
  2422.         }
  2423.  
  2424.         /**
  2425.          * Return the nth Accessible child of the object.
  2426.          *
  2427.          * @param i zero-based index of child
  2428.          * @return the nth Accessible child of the object
  2429.          */
  2430.         public Accessible getAccessibleChild(int i) {
  2431.             TreeModel model = JTree.this.getModel();
  2432.             if (model != null) {
  2433.                 if (i < 0 || i >= model.getChildCount(model.getRoot())) {
  2434.                     return null;
  2435.                 } else {
  2436.                     Object o = model.getChild(model.getRoot(), i);
  2437.                     Object[] objPath = {model.getRoot(), o};
  2438.                     TreePath path = new TreePath(objPath);
  2439.                     return new AccessibleJTreeNode(JTree.this, path, JTree.this);
  2440.                 }
  2441.             }
  2442.             return null;
  2443.         }
  2444.  
  2445.  
  2446.         // AccessibleSelection methods
  2447.  
  2448.         public AccessibleSelection getAccessibleSelection() {
  2449.             return this;
  2450.         }
  2451.  
  2452.         /**
  2453.          * Returns the number of items currently selected.
  2454.          * If no items are selected, the return value will be 0.
  2455.          *
  2456.          * @return the number of items currently selected.
  2457.          */
  2458.         public int getAccessibleSelectionCount() {
  2459.             return JTree.this.getSelectionCount();
  2460.         }
  2461.  
  2462.         /**
  2463.          * Returns an Accessible representing the specified selected item
  2464.          * in the object.  If there isn't a selection, or there are 
  2465.          * fewer items selcted than the integer passed in, the return
  2466.          * value will be null.
  2467.          *
  2468.          * @param i the zero-based index of selected items
  2469.          * @return an Accessible containing the selected item
  2470.          */
  2471.         public Accessible getAccessibleSelection(int i) {
  2472.             TreePath[] paths = JTree.this.getSelectionPaths();
  2473.             if (i < 0 || i >= paths.length) {
  2474.                 return null;
  2475.             } else {
  2476.                 return new AccessibleJTreeNode(JTree.this, paths[i], JTree.this);
  2477.             }
  2478.         }
  2479.  
  2480.         /**
  2481.          * Returns true if the current child of this object is selected.
  2482.          *
  2483.          * @param i the zero-based index of the child in this Accessible object.
  2484.          * @see AccessibleContext#getAccessibleChild
  2485.          */
  2486.         public boolean isAccessibleChildSelected(int i) {
  2487.             TreePath[] paths = JTree.this.getSelectionPaths();
  2488.             TreeModel treeModel = JTree.this.getModel();
  2489.             Object o;
  2490.             for (int j = 0; j < paths.length; j++) {
  2491.                 o = paths[j].getLastPathComponent();
  2492.                 if (i == treeModel.getIndexOfChild(treeModel.getRoot(), o)) {
  2493.                     return true;
  2494.                 }
  2495.             }
  2496.             return false;
  2497.         }
  2498.  
  2499.         /**
  2500.          * Adds the specified selected item in the object to the object's
  2501.          * selection.  If the object supports multiple selections,
  2502.          * the specified item is added to any existing selection, otherwise
  2503.          * it replaces any existing selection in the object.  If the
  2504.          * specified item is already selected, this method has no effect.
  2505.          *
  2506.          * @param i the zero-based index of selectable items
  2507.          */
  2508.         public void addAccessibleSelection(int i) {
  2509.            TreeModel model = JTree.this.getModel();
  2510.            if (model != null) {
  2511.                if (i >= 0 && i < model.getChildCount(model.getRoot())) {
  2512.                    Object o = model.getChild(model.getRoot(), i);
  2513.                    Object[] objPath = {model.getRoot(), o};
  2514.                    TreePath path = new TreePath(objPath);
  2515.                    JTree.this.addSelectionPath(path);
  2516.                 }
  2517.             }
  2518.         }
  2519.  
  2520.         /**
  2521.          * Removes the specified selected item in the object from the object's
  2522.          * selection.  If the specified item isn't currently selected, this
  2523.          * method has no effect.
  2524.          *
  2525.          * @param i the zero-based index of selectable items
  2526.          */
  2527.         public void removeAccessibleSelection(int i) {
  2528.            TreeModel model = JTree.this.getModel();
  2529.            if (model != null) {
  2530.                if (i >= 0 && i < model.getChildCount(model.getRoot())) {
  2531.                    Object o = model.getChild(model.getRoot(), i);
  2532.                    Object[] objPath = {model.getRoot(), o};
  2533.                    TreePath path = new TreePath(objPath);
  2534.                    JTree.this.removeSelectionPath(path);
  2535.                 }
  2536.             }
  2537.         }
  2538.  
  2539.         /**
  2540.          * Clears the selection in the object, so that nothing in the
  2541.          * object is selected.
  2542.          */
  2543.         public void clearAccessibleSelection() {
  2544.             int childCount = getAccessibleChildrenCount();
  2545.             for (int i = 0; i < childCount; i++) {
  2546.                 removeAccessibleSelection(i);
  2547.             }
  2548.         }
  2549.  
  2550.         /**
  2551.          * Causes every selected item in the object to be selected
  2552.          * if the object supports multiple selections.
  2553.          */
  2554.         public void selectAllAccessibleSelection() {
  2555.             TreeModel model = JTree.this.getModel();
  2556.             if (model != null) {
  2557.                JTree.this.addSelectionInterval(0, model.getChildCount(model.getRoot())-1);
  2558.             }
  2559.         }
  2560.  
  2561.         /**
  2562.          *
  2563.          */
  2564.         protected class AccessibleJTreeNode extends AccessibleContext
  2565.             implements Accessible, AccessibleComponent, AccessibleSelection, 
  2566.             AccessibleAction {
  2567.  
  2568.             private JTree tree = null;
  2569.             private TreeModel treeModel = null;
  2570.             private Object obj = null;
  2571.             private Object objParent = null;
  2572.             private TreePath path = null;
  2573.             private Accessible accessibleParent = null;
  2574.             private int index = -1;
  2575.             private boolean isLeaf = false;
  2576.  
  2577.             /**
  2578.              *  Constructs an AccessibleJTreeNode
  2579.              */
  2580.             public AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {
  2581.                 tree = t;
  2582.                 path = p;
  2583.                 accessibleParent = ap;
  2584.                 treeModel = t.getModel();
  2585.                 obj = p.getLastPathComponent();
  2586.                 Object[] objPath = p.getPath();
  2587.                 if (objPath.length > 1) {
  2588.                     objParent = objPath[objPath.length-2];
  2589.                     if (treeModel != null) {
  2590.                         index = treeModel.getIndexOfChild(objParent, obj);
  2591.                     }
  2592.                     Object[] objParentPath = new Object[objPath.length-1];
  2593.                     java.lang.System.arraycopy(objPath, 0, objParentPath, 0, objPath.length-1);
  2594.                     TreePath parentPath = new TreePath(objParentPath);
  2595.                     this.setAccessibleParent(accessibleParent);
  2596.                 } else {
  2597.                     if (treeModel != null) {
  2598.                         index = treeModel.getIndexOfChild(treeModel.getRoot(), obj);
  2599.                         this.setAccessibleParent(tree);
  2600.                     }
  2601.                 }
  2602.                 if (treeModel != null) {
  2603.                     isLeaf = treeModel.isLeaf(obj);
  2604.                 }
  2605.             }
  2606.  
  2607.             private TreePath getChildTreePath(int i) {
  2608.                 // Tree nodes can't be so complex that they have
  2609.                 // two sets of children -> we're ignoring that case
  2610.                 if (i < 0 || i >= getAccessibleChildrenCount()) {
  2611.                     return null;
  2612.                 } else {
  2613.                     Object childObj = treeModel.getChild(obj, i);
  2614.                     Object[] objPath = path.getPath();
  2615.                     Object[] objChildPath = new Object[objPath.length+1];
  2616.                     java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
  2617.                     objChildPath[objChildPath.length-1] = childObj;
  2618.                     return new TreePath(objChildPath);
  2619.                 }
  2620.             }
  2621.  
  2622.             /**
  2623.              * Get the AccessibleContext associated with this tree node
  2624.              *
  2625.              * @return the AccessibleContext of this JComponent
  2626.              */
  2627.             public AccessibleContext getAccessibleContext() {
  2628.                 return this;
  2629.             }
  2630.  
  2631.             private AccessibleContext getCurrentAccessibleContext() {
  2632.                 Component c = getCurrentComponent();
  2633.                 if (c instanceof Accessible) {
  2634.                     return (((Accessible) c).getAccessibleContext());
  2635.                 } else {
  2636.                     return null;
  2637.                 }
  2638.             }
  2639.  
  2640.             private Component getCurrentComponent() {
  2641.                 // is the object visible?
  2642.                 // if so, get row, selected, focus & leaf state, 
  2643.                 // and then get the renderer component and return it
  2644.                 if (tree.isVisible(path)) {
  2645.                     TreeCellRenderer r = tree.getCellRenderer();
  2646.                     TreeUI ui = tree.getUI();
  2647.                     if (ui != null) {
  2648.                         int row = ui.getRowForPath(path);
  2649.                         boolean selected = tree.isPathSelected(path);
  2650.                         boolean expanded = tree.isExpanded(path);
  2651.                         boolean hasFocus = false; // how to tell?? -PK
  2652.                         return r.getTreeCellRendererComponent(tree, obj, 
  2653.                             selected, expanded, isLeaf, row, hasFocus);
  2654.                     }
  2655.                 } 
  2656.                 return null;
  2657.             }
  2658.  
  2659.         // AccessibleContext methods
  2660.     
  2661.              /**
  2662.               * Get the accessible name of this object.
  2663.               *
  2664.               * @return the localized name of the object; null if this 
  2665.               * object does not have a name
  2666.               */
  2667.              public String getAccessibleName() {
  2668.                 AccessibleContext ac = getCurrentAccessibleContext();
  2669.                 if (ac != null) {
  2670.                     String name = ac.getAccessibleName();
  2671.                     if ((name != null) && (name != "")) {
  2672.                         return ac.getAccessibleName();
  2673.                     } else {
  2674.                         return null;
  2675.                     }
  2676.                 }
  2677.                 if ((accessibleName != null) && (accessibleName != "")) {
  2678.                     return accessibleName;
  2679.                 } else {
  2680.                     return null;
  2681.                 }
  2682.             }
  2683.     
  2684.             /**
  2685.              * Set the localized accessible name of this object.
  2686.              *
  2687.              * @param s the new localized name of the object.
  2688.              */
  2689.             public void setAccessibleName(String s) {
  2690.                 AccessibleContext ac = getCurrentAccessibleContext();
  2691.                 if (ac != null) {
  2692.                     ac.setAccessibleName(s);
  2693.                 } else {
  2694.                     super.setAccessibleName(s);
  2695.                 }
  2696.             }
  2697.     
  2698.             //
  2699.             // *** should check toolip text for desc. (needs MouseEvent)
  2700.             //
  2701.             /**
  2702.              * Get the accessible description of this object.
  2703.              *
  2704.              * @return the localized description of the object; null if 
  2705.              * this object does not have a description
  2706.              */
  2707.             public String getAccessibleDescription() {
  2708.                 AccessibleContext ac = getCurrentAccessibleContext();
  2709.                 if (ac != null) {
  2710.                     return ac.getAccessibleDescription();
  2711.                 } else {
  2712.                     return super.getAccessibleDescription();
  2713.                 }
  2714.             }
  2715.     
  2716.             /**
  2717.              * Set the accessible description of this object.
  2718.              *
  2719.              * @param s the new localized description of the object
  2720.              */
  2721.             public void setAccessibleDescription(String s) {
  2722.                 AccessibleContext ac = getCurrentAccessibleContext();
  2723.                 if (ac != null) {
  2724.                     ac.setAccessibleDescription(s);
  2725.                 } else {
  2726.                     super.setAccessibleDescription(s);
  2727.                 }
  2728.             }
  2729.     
  2730.             /**
  2731.              * Get the role of this object.
  2732.              *
  2733.              * @return an instance of AccessibleRole describing the role of the object
  2734.              * @see AccessibleRole
  2735.              */
  2736.             public AccessibleRole getAccessibleRole() {
  2737.                 AccessibleContext ac = getCurrentAccessibleContext();
  2738.                 if (ac != null) {
  2739.                     return ac.getAccessibleRole();
  2740.                 } else {
  2741.                     return AccessibleRole.UNKNOWN;
  2742.                 }
  2743.             }
  2744.     
  2745.             /**
  2746.              * Get the state set of this object.
  2747.              *
  2748.              * @return an instance of AccessibleStateSet containing the 
  2749.              * current state set of the object
  2750.              * @see AccessibleState
  2751.              */
  2752.             public AccessibleStateSet getAccessibleStateSet() {
  2753.                 AccessibleContext ac = getCurrentAccessibleContext();
  2754.                 AccessibleStateSet states;
  2755.                 if (ac != null) {
  2756.                     states = ac.getAccessibleStateSet();
  2757.                 } else {
  2758.                     states = new AccessibleStateSet();
  2759.                 }
  2760.                 // need to test here, 'cause the underlying component 
  2761.                 // is a cellRenderer, which is never showing...
  2762.                 if (isShowing()) {
  2763.                     states.add(AccessibleState.SHOWING);
  2764.                 } else if (states.contains(AccessibleState.SHOWING)) {
  2765.                     states.remove(AccessibleState.SHOWING);
  2766.         }
  2767.                 if (isVisible()) {
  2768.                     states.add(AccessibleState.VISIBLE);
  2769.                 } else if (states.contains(AccessibleState.VISIBLE)) {
  2770.                     states.remove(AccessibleState.VISIBLE);
  2771.         }
  2772.                 if (tree.isPathSelected(path)){
  2773.                     states.add(AccessibleState.SELECTED);
  2774.                 }
  2775.                 if (!isLeaf) {
  2776.                     states.add(AccessibleState.EXPANDABLE);
  2777.                 }
  2778.                 if (tree.isExpanded(path)) {
  2779.                     states.add(AccessibleState.EXPANDED);
  2780.                 } else {
  2781.                     states.add(AccessibleState.COLLAPSED);
  2782.                 }
  2783.                 if (tree.isEditable()) {
  2784.                     states.add(AccessibleState.EDITABLE);
  2785.                 }
  2786.                 return states;
  2787.             }
  2788.     
  2789.             /**
  2790.              * Get the Accessible parent of this object.
  2791.              *
  2792.              * @return the Accessible parent of this object; null if this
  2793.              * object does not have an Accessible parent
  2794.              */
  2795.             public Accessible getAccessibleParent() {
  2796.                 return accessibleParent;
  2797.             }
  2798.     
  2799.             /**
  2800.              * Get the index of this object in its accessible parent. 
  2801.              *
  2802.              * @return the index of this object in its parent; -1 if this 
  2803.              * object does not have an accessible parent.
  2804.              * @see #getAccessibleParent
  2805.              */
  2806.             public int getAccessibleIndexInParent() {
  2807.                 return index;
  2808.             }
  2809.     
  2810.             /**
  2811.              * Returns the number of accessible children in the object.
  2812.              *
  2813.              * @return the number of accessible children in the object.
  2814.              */
  2815.             public int getAccessibleChildrenCount() {
  2816.                 // Tree nodes can't be so complex that they have 
  2817.                 // two sets of children -> we're ignoring that case
  2818.                 return treeModel.getChildCount(obj);
  2819.             }
  2820.     
  2821.             /**
  2822.              * Return the specified Accessible child of the object.
  2823.              *
  2824.              * @param i zero-based index of child
  2825.              * @return the Accessible child of the object
  2826.              */
  2827.             public Accessible getAccessibleChild(int i) {
  2828.                 // Tree nodes can't be so complex that they have 
  2829.                 // two sets of children -> we're ignoring that case
  2830.                 if (i < 0 || i >= getAccessibleChildrenCount()) {
  2831.                     return null;
  2832.                 } else {
  2833.                     Object childObj = treeModel.getChild(obj, i);
  2834.                     Object[] objPath = path.getPath();
  2835.                     Object[] objChildPath = new Object[objPath.length+1];
  2836.                     java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
  2837.                     objChildPath[objChildPath.length-1] = childObj;
  2838.                     TreePath childPath = new TreePath(objChildPath);
  2839.                     return new AccessibleJTreeNode(JTree.this, childPath, this);
  2840.                 }
  2841.             }
  2842.     
  2843.             /** 
  2844.              * Gets the locale of the component. If the component does not have a 
  2845.              * locale, then the locale of its parent is returned.  
  2846.              *
  2847.              * @return This component's locale. If this component does not have a locale, the locale of its parent is returned.
  2848.              * @exception IllegalComponentStateException 
  2849.              * If the Component does not have its own locale and has not yet been added to a containment hierarchy such that the locale can be
  2850.              * determined from the containing parent. 
  2851.              * @see setLocale
  2852.              */
  2853.             public Locale getLocale() {
  2854.                 AccessibleContext ac = getCurrentAccessibleContext();
  2855.                 if (ac != null) {
  2856.                     return ac.getLocale();
  2857.                 } else {
  2858.                     return tree.getLocale();
  2859.                 }
  2860.             }
  2861.     
  2862.             /**
  2863.              * Add a PropertyChangeListener to the listener list.
  2864.              * The listener is registered for all properties.
  2865.              *
  2866.              * @param listener  The PropertyChangeListener to be added
  2867.              */
  2868.             public void addPropertyChangeListener(PropertyChangeListener l) {
  2869.                 AccessibleContext ac = getCurrentAccessibleContext();
  2870.                 if (ac != null) {
  2871.                     ac.addPropertyChangeListener(l);
  2872.                 } else {
  2873.                     super.addPropertyChangeListener(l);
  2874.                 }
  2875.             }
  2876.     
  2877.             /**
  2878.              * Remove a PropertyChangeListener from the listener list.
  2879.              * This removes a PropertyChangeListener that was registered
  2880.              * for all properties.
  2881.              *
  2882.              * @param listener  The PropertyChangeListener to be removed
  2883.              */
  2884.             public void removePropertyChangeListener(PropertyChangeListener l) {
  2885.                 AccessibleContext ac = getCurrentAccessibleContext();
  2886.                 if (ac != null) {
  2887.                     ac.removePropertyChangeListener(l);
  2888.                 } else {
  2889.                     super.removePropertyChangeListener(l);
  2890.                 }
  2891.             }
  2892.     
  2893.             /**
  2894.              * Get the AccessibleAction associated with this object if one
  2895.              * exists.  Otherwise return null.
  2896.              *
  2897.              * @return the AccessibleAction, or null
  2898.              */
  2899.             public AccessibleAction getAccessibleAction() {
  2900.                 return this;
  2901.             }
  2902.  
  2903.             /**
  2904.              * Get the AccessibleComponent associated with this tree node
  2905.              * NOTE: if the node is not visible (either scrolled off of
  2906.              * the screen, or not expanded), this will return null
  2907.              *
  2908.              * @return the AccessibleComponent of this tree node
  2909.              */
  2910.             public AccessibleComponent getAccessibleComponent() {
  2911.                 return this; // to override getBounds()
  2912.             }
  2913.  
  2914.             /**
  2915.              * Get the AccessibleSelection associated with this object if one
  2916.              * exists.  Otherwise return null.
  2917.              *
  2918.              * @return the AccessibleSelection, or null
  2919.              */
  2920.             public AccessibleSelection getAccessibleSelection() {
  2921.                 AccessibleContext ac = getCurrentAccessibleContext();
  2922.                 if (ac != null && isLeaf) {
  2923.                     return getCurrentAccessibleContext().getAccessibleSelection();
  2924.                 } else {
  2925.                     return this;
  2926.                 }
  2927.             }
  2928.  
  2929.             /**
  2930.              * Get the AccessibleText associated with this object if one
  2931.              * exists.  Otherwise return null.
  2932.              *
  2933.              * @return the AccessibleText, or null
  2934.              */
  2935.             public AccessibleText getAccessibleText() {
  2936.                 AccessibleContext ac = getCurrentAccessibleContext();
  2937.                 if (ac != null) {
  2938.                     return getCurrentAccessibleContext().getAccessibleText();
  2939.                 } else {
  2940.                     return null;
  2941.                 }
  2942.             }
  2943.  
  2944.             /**
  2945.              * Get the AccessibleValue associated with this object if one
  2946.              * exists.  Otherwise return null.
  2947.              *
  2948.              * @return the AccessibleValue, or null
  2949.              */
  2950.             public AccessibleValue getAccessibleValue() {
  2951.                 AccessibleContext ac = getCurrentAccessibleContext();
  2952.                 if (ac != null) {
  2953.                     return getCurrentAccessibleContext().getAccessibleValue();
  2954.                 } else {
  2955.                     return null;
  2956.                 }
  2957.             }
  2958.  
  2959.  
  2960.         // AccessibleComponent methods
  2961.     
  2962.             /**
  2963.              * Get the background color of this object.
  2964.              *
  2965.              * @return the background color, if supported, of the object; 
  2966.              * otherwise, null
  2967.              */
  2968.             public Color getBackground() {
  2969.                 AccessibleContext ac = getCurrentAccessibleContext();
  2970.                 if (ac instanceof AccessibleComponent) {
  2971.                     return ((AccessibleComponent) ac).getBackground();
  2972.                 } else {
  2973.                     Component c = getCurrentComponent();
  2974.                     if (c != null) {
  2975.                         return c.getBackground();
  2976.                     } else {
  2977.                         return null;
  2978.                     }
  2979.                 }
  2980.             }
  2981.     
  2982.             /**
  2983.              * Set the background color of this object.
  2984.              *
  2985.              * @param c the new Color for the background
  2986.              */
  2987.             public void setBackground(Color c) {
  2988.                 AccessibleContext ac = getCurrentAccessibleContext();
  2989.                 if (ac instanceof AccessibleComponent) {
  2990.                     ((AccessibleComponent) ac).setBackground(c);
  2991.                 } else {
  2992.                     Component cp = getCurrentComponent();
  2993.                     if (cp != null) {
  2994.                         cp.setBackground(c);
  2995.                     }
  2996.                 }
  2997.             }
  2998.     
  2999.         
  3000.             /**
  3001.              * Get the foreground color of this object.
  3002.              *
  3003.              * @return the foreground color, if supported, of the object; 
  3004.              * otherwise, null
  3005.              */
  3006.             public Color getForeground() {
  3007.                 AccessibleContext ac = getCurrentAccessibleContext();
  3008.                 if (ac instanceof AccessibleComponent) {
  3009.                     return ((AccessibleComponent) ac).getForeground();
  3010.                 } else {
  3011.                     Component c = getCurrentComponent();
  3012.                     if (c != null) {
  3013.                         return c.getForeground();
  3014.                     } else {
  3015.                         return null;
  3016.                     }
  3017.                 }
  3018.             }
  3019.     
  3020.             public void setForeground(Color c) {
  3021.                 AccessibleContext ac = getCurrentAccessibleContext();
  3022.                 if (ac instanceof AccessibleComponent) {
  3023.                     ((AccessibleComponent) ac).setForeground(c);
  3024.                 } else {
  3025.                     Component cp = getCurrentComponent();
  3026.                     if (cp != null) {
  3027.                         cp.setForeground(c);
  3028.                     }
  3029.                 }
  3030.             }
  3031.     
  3032.             public Cursor getCursor() {
  3033.                 AccessibleContext ac = getCurrentAccessibleContext();
  3034.                 if (ac instanceof AccessibleComponent) {
  3035.                     return ((AccessibleComponent) ac).getCursor();
  3036.                 } else {
  3037.                     Component c = getCurrentComponent();
  3038.                     if (c != null) {
  3039.                         return c.getCursor();
  3040.                     } else {
  3041.                         Accessible ap = getAccessibleParent();
  3042.                         if (ap instanceof AccessibleComponent) {
  3043.                             return ((AccessibleComponent) ap).getCursor();
  3044.                         } else {
  3045.                             return null;
  3046.                         }
  3047.                     }
  3048.                 }
  3049.             }
  3050.     
  3051.             public void setCursor(Cursor c) {
  3052.                 AccessibleContext ac = getCurrentAccessibleContext();
  3053.                 if (ac instanceof AccessibleComponent) {
  3054.                     ((AccessibleComponent) ac).setCursor(c);
  3055.                 } else {
  3056.                     Component cp = getCurrentComponent();
  3057.                     if (cp != null) {
  3058.                         cp.setCursor(c);
  3059.                     }
  3060.                 }
  3061.             }
  3062.     
  3063.             public Font getFont() {
  3064.                 AccessibleContext ac = getCurrentAccessibleContext();
  3065.                 if (ac instanceof AccessibleComponent) {
  3066.                     return ((AccessibleComponent) ac).getFont();
  3067.                 } else {
  3068.                     Component c = getCurrentComponent();
  3069.                     if (c != null) {
  3070.                         return c.getFont();
  3071.                     } else {
  3072.                         return null;
  3073.                     }
  3074.                 }
  3075.             }
  3076.     
  3077.             public void setFont(Font f) {
  3078.                 AccessibleContext ac = getCurrentAccessibleContext();
  3079.                 if (ac instanceof AccessibleComponent) {
  3080.                     ((AccessibleComponent) ac).setFont(f);
  3081.                 } else {
  3082.                     Component c = getCurrentComponent();
  3083.                     if (c != null) {
  3084.                         c.setFont(f);
  3085.                     }
  3086.                 }
  3087.             }
  3088.     
  3089.             public FontMetrics getFontMetrics(Font f) {
  3090.                 AccessibleContext ac = getCurrentAccessibleContext();
  3091.                 if (ac instanceof AccessibleComponent) {
  3092.                     return ((AccessibleComponent) ac).getFontMetrics(f);
  3093.                 } else {
  3094.                     Component c = getCurrentComponent();
  3095.                     if (c != null) {
  3096.                         return c.getFontMetrics(f);
  3097.                     } else {
  3098.                         return null;
  3099.                     }
  3100.                 }
  3101.             }
  3102.     
  3103.             public boolean isEnabled() {
  3104.                 AccessibleContext ac = getCurrentAccessibleContext();
  3105.                 if (ac instanceof AccessibleComponent) {
  3106.                     return ((AccessibleComponent) ac).isEnabled();
  3107.                 } else {
  3108.                     Component c = getCurrentComponent();
  3109.                     if (c != null) {
  3110.                         return c.isEnabled();
  3111.                     } else {
  3112.                         return false;
  3113.                     }
  3114.                 }
  3115.             }
  3116.     
  3117.             public void setEnabled(boolean b) {
  3118.                 AccessibleContext ac = getCurrentAccessibleContext();
  3119.                 if (ac instanceof AccessibleComponent) {
  3120.                     ((AccessibleComponent) ac).setEnabled(b);
  3121.                 } else {
  3122.                     Component c = getCurrentComponent();
  3123.                     if (c != null) {
  3124.                         c.setEnabled(b);
  3125.                     }
  3126.                 }
  3127.             }
  3128.     
  3129.             public boolean isVisible() {
  3130.         Rectangle pathBounds = tree.getPathBounds(path);
  3131.         Rectangle parentBounds = tree.getVisibleRect();
  3132.         if (pathBounds != null && parentBounds != null && 
  3133.             parentBounds.intersects(pathBounds)) {
  3134.                     return true;
  3135.                 } else {
  3136.                     return false;
  3137.                 }
  3138.             }
  3139.     
  3140.             public void setVisible(boolean b) {
  3141.             }
  3142.     
  3143.         public boolean isShowing() {
  3144.             return (tree.isShowing() && isVisible());
  3145.             }
  3146.     
  3147.             public boolean contains(Point p) {
  3148.                 AccessibleContext ac = getCurrentAccessibleContext();
  3149.                 if (ac instanceof AccessibleComponent) {
  3150.                     Rectangle r = ((AccessibleComponent) ac).getBounds();
  3151.                     return r.contains(p);
  3152.                 } else {
  3153.                     Component c = getCurrentComponent();
  3154.                     if (c != null) {
  3155.                         Rectangle r = c.getBounds();
  3156.                         return r.contains(p);
  3157.                     } else {
  3158.                         return getBounds().contains(p);
  3159.                     }
  3160.                 }
  3161.             }
  3162.     
  3163.             public Point getLocationOnScreen() {
  3164.                 if (tree != null) {
  3165.                     Point parentLocation = tree.getLocationOnScreen();
  3166.                     Point componentLocation = getLocation();
  3167.                     componentLocation.translate(parentLocation.x, parentLocation.y);
  3168.                     return componentLocation;
  3169.                 } else {
  3170.                     return null;
  3171.                 }
  3172.             }
  3173.     
  3174.             protected Point getLocationInJTree() {
  3175.                 Rectangle r = tree.getPathBounds(path);
  3176.                 if (r != null) {
  3177.                     return r.getLocation();
  3178.                 } else {
  3179.                     return null;
  3180.                 }
  3181.             }
  3182.  
  3183.             public Point getLocation() {
  3184.                 Rectangle r = getBounds();
  3185.                 if (r != null) {
  3186.                     return r.getLocation();
  3187.                 } else {
  3188.                     return null;
  3189.                 }
  3190.             }
  3191.     
  3192.             public void setLocation(Point p) {
  3193.             }
  3194.                 
  3195.             public Rectangle getBounds() {
  3196.                 Rectangle r = tree.getPathBounds(path);
  3197.                 Accessible parent = getAccessibleParent();
  3198.                 if (parent != null) {
  3199.                     if (parent instanceof AccessibleJTreeNode) {
  3200.                         Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();
  3201.                         if (parentLoc != null && r != null) {
  3202.                             r.translate(-parentLoc.x, -parentLoc.y);
  3203.                         } else {
  3204.                             return null;        // not visible!
  3205.                         }
  3206.                     } 
  3207.                 }
  3208.                 return r;
  3209.             }
  3210.     
  3211.             public void setBounds(Rectangle r) {
  3212.                 AccessibleContext ac = getCurrentAccessibleContext();
  3213.                 if (ac instanceof AccessibleComponent) {
  3214.                     ((AccessibleComponent) ac).setBounds(r);
  3215.                 } else {
  3216.                     Component c = getCurrentComponent();
  3217.                     if (c != null) {
  3218.                         c.setBounds(r);
  3219.                     }
  3220.                 }
  3221.             }
  3222.     
  3223.             public Dimension getSize() {
  3224.                 return getBounds().getSize();
  3225.             }
  3226.     
  3227.             public void setSize (Dimension d) {
  3228.                 AccessibleContext ac = getCurrentAccessibleContext();
  3229.                 if (ac instanceof AccessibleComponent) {
  3230.                     ((AccessibleComponent) ac).setSize(d);
  3231.                 } else {
  3232.                     Component c = getCurrentComponent();
  3233.                     if (c != null) {
  3234.                         c.setSize(d);
  3235.                     }
  3236.                 }
  3237.             }
  3238.     
  3239.             public Accessible getAccessibleAt(Point p) {
  3240.                 AccessibleContext ac = getCurrentAccessibleContext();
  3241.                 if (ac instanceof AccessibleComponent) {
  3242.                     return ((AccessibleComponent) ac).getAccessibleAt(p);
  3243.                 } else {
  3244.                     return null;
  3245.                 }
  3246.             }
  3247.     
  3248.             public boolean isFocusTraversable() {
  3249.                 AccessibleContext ac = getCurrentAccessibleContext();
  3250.                 if (ac instanceof AccessibleComponent) {
  3251.                     return ((AccessibleComponent) ac).isFocusTraversable();
  3252.                 } else {
  3253.                     Component c = getCurrentComponent();
  3254.                     if (c != null) {
  3255.                         return c.isFocusTraversable();
  3256.                     } else {
  3257.                         return false;
  3258.                     }
  3259.                 }
  3260.             }
  3261.     
  3262.             public void requestFocus() {
  3263.                 AccessibleContext ac = getCurrentAccessibleContext();
  3264.                 if (ac instanceof AccessibleComponent) {
  3265.                     ((AccessibleComponent) ac).requestFocus();
  3266.                 } else {
  3267.                     Component c = getCurrentComponent();
  3268.                     if (c != null) {
  3269.                         c.requestFocus();
  3270.                     }
  3271.                 }
  3272.             }
  3273.     
  3274.             public void addFocusListener(FocusListener l) {
  3275.                 AccessibleContext ac = getCurrentAccessibleContext();
  3276.                 if (ac instanceof AccessibleComponent) {
  3277.                     ((AccessibleComponent) ac).addFocusListener(l);
  3278.                 } else {
  3279.                     Component c = getCurrentComponent();
  3280.                     if (c != null) {
  3281.                         c.addFocusListener(l);
  3282.                     }
  3283.                 }
  3284.             }
  3285.     
  3286.             public void removeFocusListener(FocusListener l) {
  3287.                 AccessibleContext ac = getCurrentAccessibleContext();
  3288.                 if (ac instanceof AccessibleComponent) {
  3289.                     ((AccessibleComponent) ac).removeFocusListener(l);
  3290.                 } else {
  3291.                     Component c = getCurrentComponent();
  3292.                     if (c != null) {
  3293.                         c.removeFocusListener(l);
  3294.                     }
  3295.                 }
  3296.             }
  3297.  
  3298.         // AccessibleSelection methods
  3299.  
  3300.             /**
  3301.              * Returns the number of items currently selected.
  3302.              * If no items are selected, the return value will be 0.
  3303.              *
  3304.              * @return the number of items currently selected.
  3305.              */
  3306.             public int getAccessibleSelectionCount() {
  3307.                 int count = 0;
  3308.                 int childCount = getAccessibleChildrenCount();
  3309.                 for (int i = 0; i < childCount; i++) {
  3310.                     TreePath childPath = getChildTreePath(i);
  3311.                     if (tree.isPathSelected(childPath)) {
  3312.                        count++;
  3313.                     }
  3314.                 } 
  3315.                 return count;
  3316.             }
  3317.  
  3318.             /**
  3319.              * Returns an Accessible representing the specified selected item
  3320.              * in the object.  If there isn't a selection, or there are 
  3321.              * fewer items selcted than the integer passed in, the return
  3322.              * value will be null.
  3323.              *
  3324.              * @param i the zero-based index of selected items
  3325.              * @return an Accessible containing the selected item
  3326.              */
  3327.             public Accessible getAccessibleSelection(int i) {
  3328.                 int childCount = getAccessibleChildrenCount();
  3329.                 if (i < 0 || i >= childCount) {
  3330.                     return null;        // out of range
  3331.                 }
  3332.                 int count = 0;
  3333.                 for (int j = 0; j < childCount && i >= count; j++) {
  3334.                     TreePath childPath = getChildTreePath(j);
  3335.                     if (tree.isPathSelected(childPath)) { 
  3336.                         if (count == i) {
  3337.                             return new AccessibleJTreeNode(tree, childPath, this);
  3338.                         } else {
  3339.                             count++;
  3340.                         }
  3341.                     }
  3342.                 }
  3343.                 return null;
  3344.             }
  3345.  
  3346.             /**
  3347.              * Returns true if the current child of this object is selected.
  3348.              *
  3349.              * @param i the zero-based index of the child in this Accessible 
  3350.              * object.
  3351.              * @see AccessibleContext#getAccessibleChild
  3352.              */
  3353.             public boolean isAccessibleChildSelected(int i) {
  3354.                 int childCount = getAccessibleChildrenCount();
  3355.                 if (i < 0 || i >= childCount) {
  3356.                     return false;       // out of range
  3357.                 } else {
  3358.                     TreePath childPath = getChildTreePath(i);
  3359.                     return tree.isPathSelected(childPath);
  3360.                 }
  3361.             }
  3362.  
  3363.             /**
  3364.              * Adds the specified selected item in the object to the object's
  3365.              * selection.  If the object supports multiple selections,
  3366.              * the specified item is added to any existing selection, otherwise
  3367.              * it replaces any existing selection in the object.  If the
  3368.              * specified item is already selected, this method has no effect.
  3369.              *
  3370.              * @param i the zero-based index of selectable items
  3371.              */
  3372.             public void addAccessibleSelection(int i) {
  3373.                TreeModel model = JTree.this.getModel();
  3374.                if (model != null) {
  3375.                    if (i >= 0 && i < getAccessibleChildrenCount()) {
  3376.                        TreePath path = getChildTreePath(i);
  3377.                        JTree.this.addSelectionPath(path);
  3378.                     }
  3379.                 }
  3380.             }
  3381.  
  3382.             /**
  3383.              * Removes the specified selected item in the object from the 
  3384.              * object's
  3385.              * selection.  If the specified item isn't currently selected, this
  3386.              * method has no effect.
  3387.              *
  3388.              * @param i the zero-based index of selectable items
  3389.              */
  3390.             public void removeAccessibleSelection(int i) {
  3391.                TreeModel model = JTree.this.getModel();
  3392.                if (model != null) {
  3393.                    if (i >= 0 && i < getAccessibleChildrenCount()) {
  3394.                        TreePath path = getChildTreePath(i);
  3395.                        JTree.this.removeSelectionPath(path);
  3396.                     }
  3397.                 }
  3398.             }
  3399.  
  3400.             /**
  3401.              * Clears the selection in the object, so that nothing in the
  3402.              * object is selected.
  3403.              */
  3404.             public void clearAccessibleSelection() {
  3405.                 int childCount = getAccessibleChildrenCount();
  3406.                 for (int i = 0; i < childCount; i++) {
  3407.                     removeAccessibleSelection(i);
  3408.                 }
  3409.             }
  3410.  
  3411.             /**
  3412.              * Causes every selected item in the object to be selected
  3413.              * if the object supports multiple selections.
  3414.              */
  3415.             public void selectAllAccessibleSelection() {
  3416.                TreeModel model = JTree.this.getModel();
  3417.                if (model != null) {
  3418.                    int childCount = getAccessibleChildrenCount();
  3419.                    TreePath path;
  3420.                    for (int i = 0; i < childCount; i++) {
  3421.                        path = getChildTreePath(i);
  3422.                        JTree.this.addSelectionPath(path);
  3423.                    }
  3424.                 }
  3425.             }
  3426.  
  3427.         // AccessibleAction methods
  3428.  
  3429.             /**
  3430.              * Returns the number of accessible actions available in this 
  3431.              * tree node.  If this node is not a leaf, there is at least 
  3432.              * one action (toggle expand), in addition to any available
  3433.              * on the object behind the TreeCellRenderer.
  3434.              *
  3435.              * @return the number of Actions in this object
  3436.              */
  3437.             public int getAccessibleActionCount() {
  3438.                 AccessibleContext ac = getCurrentAccessibleContext();
  3439.                 if (ac != null) {
  3440.                     AccessibleAction aa = ac.getAccessibleAction();
  3441.                     if (aa != null) {
  3442.                         return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));
  3443.                     }
  3444.                 }
  3445.                 return isLeaf ? 0 : 1;
  3446.             }
  3447.  
  3448.             /**
  3449.              * Return a description of the specified action of the tree node.
  3450.              * If this node is not a leaf, there is at least one action
  3451.              * description (toggle expand), in addition to any available
  3452.              * on the object behind the TreeCellRenderer.
  3453.              *
  3454.              * @param i zero-based index of the actions
  3455.              * @return a description of the action
  3456.              */
  3457.             public String getAccessibleActionDescription(int i) {
  3458.                 if (i < 0 || i >= getAccessibleActionCount()) {
  3459.                     return null;
  3460.                 }
  3461.                 AccessibleContext ac = getCurrentAccessibleContext();
  3462.                 if (i == 0) {
  3463.                     return "toggle expand";
  3464.                 } else if (ac != null) {
  3465.                     AccessibleAction aa = ac.getAccessibleAction();
  3466.                     if (aa != null) {
  3467.                         return aa.getAccessibleActionDescription(i - 1);
  3468.                     }
  3469.                 }
  3470.                 return null;
  3471.             }
  3472.  
  3473.             /**
  3474.              * Perform the specified Action on the tree node.  If this node
  3475.              * is not a leaf, there is at least one action which can be
  3476.              * done (toggle expand), in addition to any available on the 
  3477.              * object behind the TreeCellRenderer.
  3478.              *
  3479.              * @param i zero-based index of actions
  3480.              * @return true if the the action was performed; else false.
  3481.              */
  3482.             public boolean doAccessibleAction(int i) {
  3483.                 if (i < 0 || i >= getAccessibleActionCount()) {
  3484.                     return false;
  3485.                 }
  3486.                 AccessibleContext ac = getCurrentAccessibleContext();
  3487.                 if (i == 0) {
  3488.                     if (JTree.this.isExpanded(path)) {
  3489.                         JTree.this.collapsePath(path);
  3490.                     } else {
  3491.                         JTree.this.expandPath(path);
  3492.                     }
  3493.                     return true;
  3494.                 } else if (ac != null) {
  3495.                     AccessibleAction aa = ac.getAccessibleAction();
  3496.                     if (aa != null) {
  3497.                         return aa.doAccessibleAction(i - 1);
  3498.                     }
  3499.                 }
  3500.                 return false;
  3501.             }
  3502.  
  3503.         } // inner class AccessibleJTreeNode
  3504.  
  3505.     }  // inner class AccessibleJTree
  3506.  
  3507. } // End of class JTree
  3508.  
  3509.