1. /*
  2. * @(#)JTree.java 1.111 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.beans.*;
  11. import java.io.*;
  12. import java.util.*;
  13. import javax.swing.event.*;
  14. import javax.swing.plaf.TreeUI;
  15. import javax.swing.tree.*;
  16. import javax.accessibility.*;
  17. /**
  18. * A control that displays a set of hierarchical data as an outline.
  19. * A specific node can be identified either by a TreePath (an object
  20. * that encapsulates a node and all of its ancestors), or by its
  21. * display row, where each row in the display area displays one node.
  22. * <p>
  23. * An <i>expanded</i> node is one displays its children. A <i>collapsed</i>
  24. * node is one which hides them. A <i>hidden</i> node is one which is
  25. * under a collapsed parent. A <i>viewable</i> node is under a collapsed
  26. * parent, but may or may not be displayed. A <i>displayed</i> node
  27. * is both viewable and in the display area, where it can be seen.
  28. * <p>
  29. * These JTree methods use "visible" to mean "displayed":<ul>
  30. * <li><code>isRootVisible()</code>
  31. * <li><code>setRootVisible()</code>
  32. * <li><code>scrollPathToVisible()</code>
  33. * <li><code>scrollRowToVisible()</code>
  34. * <li><code>getVisibleRowCount()</code>
  35. * <li><code>setVisibleRowCount()</code>
  36. * </ul>
  37. * <p>
  38. * These JTree methods use "visible" to mean "viewable" (under an
  39. * expanded parent):<ul>
  40. * <li><code>isVisible()</code>
  41. * <li><code>makeVisible()</code>
  42. * </ul>
  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. * To use JTree to display compound nodes (for example, nodes containing both
  76. * a graphic icon and text), subclass {@link TreeCellRenderer} and use
  77. * {@link #setTreeCellRenderer} to tell the tree to use it. To edit such nodes,
  78. * subclass {@link TreeCellEditor} and use {@link #setTreeCellEditor}.
  79. * <p>
  80. * Like all JComponent classes, you can use {@link JComponent#registerKeyboardAction}
  81. * to associate an {@link Action} object with a {@link KeyStroke} and execute the
  82. * action under specified conditions.
  83. * <p>
  84. * See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/tree.html">How to Use Trees</a>
  85. * in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
  86. * for further documentation.
  87. * <p>
  88. * For the keyboard keys used by this component in the standard Look and
  89. * Feel (L&F) renditions, see the
  90. * <a href="doc-files/Key-Index.html#JTree">JTree</a> key assignments.
  91. * <p>
  92. * <strong>Warning:</strong>
  93. * Serialized objects of this class will not be compatible with
  94. * future Swing releases. The current serialization support is appropriate
  95. * for short term storage or RMI between applications running the same
  96. * version of Swing. A future release of Swing will provide support for
  97. * long term persistence.
  98. *
  99. * @beaninfo
  100. * attribute: isContainer false
  101. *
  102. * @version 1.78 05/11/98
  103. * @author Rob Davis
  104. * @author Ray Ryan
  105. * @author Scott Violet
  106. */
  107. public class JTree extends JComponent implements Scrollable, Accessible
  108. {
  109. /**
  110. * @see #getUIClassID
  111. * @see #readObject
  112. */
  113. private static final String uiClassID = "TreeUI";
  114. /**
  115. * The model that defines the tree displayed by this object.
  116. */
  117. transient protected TreeModel treeModel;
  118. /**
  119. * Models the set of selected nodes in this tree.
  120. */
  121. transient protected TreeSelectionModel selectionModel;
  122. /**
  123. * True if the root node is displayed, false if its children are
  124. * the highest visible nodes.
  125. */
  126. protected boolean rootVisible;
  127. /**
  128. * The cell used to draw nodes. If null, the UI uses a default
  129. * cellRenderer.
  130. */
  131. transient protected TreeCellRenderer cellRenderer;
  132. /**
  133. * Height to use for each display row. If this is <= 0 the renderer
  134. * determines the height for each row.
  135. */
  136. protected int rowHeight;
  137. /**
  138. * Maps from TreePath to Boolean indicating whether or not the
  139. * particular path is expanded. This ONLY indicates whether a
  140. * given path is expanded, and NOT if it is visible or not. That
  141. * information must be determined by visiting all the parent
  142. * paths and seeing if they are visible.
  143. */
  144. transient private Hashtable expandedState;
  145. /**
  146. * True if handles are displayed at the topmost level of the tree.
  147. * <p>
  148. * A handle is a small icon that displays adjacent to the node which
  149. * allows the user to click once to expand or collapse the node. A
  150. * common interface shows a plus sign (+) for a node which can be
  151. * expanded and a minus sign (-) for a node which can be collapsed.
  152. * Handles are always shown for nodes below the topmost level.
  153. * <p>
  154. * If the <code>rootVisible</code> setting specifies that the root
  155. * node is to be displayed, then that is the only node at the topmost
  156. * level. If the root node is not displayed, then all of its
  157. * children are at the topmost level of the tree. Handles are
  158. * always displayed for nodes other than the topmost.
  159. * <p>
  160. * If the root node isn't visible, it is generally a good to make
  161. * this value true. Otherwise, the tree looks exactly like a list,
  162. * and users may not know that the "list entries" are actually
  163. * tree nodes.
  164. *
  165. * @see #rootVisible
  166. */
  167. protected boolean showsRootHandles;
  168. /**
  169. * Creates a new event and passed it off the selectionListeners.
  170. */
  171. protected transient TreeSelectionRedirector selectionRedirector;
  172. /**
  173. * Editor for the entries. Default is null (tree is not editable).
  174. */
  175. transient protected TreeCellEditor cellEditor;
  176. /**
  177. * Is the tree editable? Default is false.
  178. */
  179. protected boolean editable;
  180. /**
  181. * Is this tree a large model? This is a code-optimization setting.
  182. * A large model can be used when the cell height is the same for all
  183. * nodes. The UI will then cache very little information and instead
  184. * continually message the model. Without a large model the UI caches
  185. * most of the information, resulting in fewer method calls to the model.
  186. * <p>
  187. * This value is only a suggestion to the UI. Not all UIs will
  188. * take advantage of it. Default value is false.
  189. */
  190. protected boolean largeModel;
  191. /**
  192. * Number of rows to make visible at one time. This value is used for
  193. * the Scrollable interface. It determines the preferred size of the
  194. * display area.
  195. */
  196. protected int visibleRowCount;
  197. /**
  198. * If true, when editing is to be stopped by way of selection changing,
  199. * data in tree changing or other means stopCellEditing is invoked, and
  200. * changes are saved. If false, cancelCellEditing is invoked, and changes
  201. * are discarded. Default is false.
  202. */
  203. protected boolean invokesStopCellEditing;
  204. /**
  205. * If true, when a node is expanded, as many of the descendants are
  206. * scrolled to be visible.
  207. */
  208. protected boolean scrollsOnExpand;
  209. /**
  210. * Number of mouse clicks before a node is expanded.
  211. */
  212. protected int toggleClickCount;
  213. /**
  214. * Updates the expandedState.
  215. */
  216. transient protected TreeModelListener treeModelListener;
  217. /**
  218. * Used when setExpandedState is invoked, will be a Stack of Stacks.
  219. */
  220. transient private Stack expandedStack;
  221. /**
  222. * Max number of stacks to keep around.
  223. */
  224. private static int TEMP_STACK_SIZE = 11;
  225. //
  226. // Bound propery names
  227. //
  228. /** Bound property name for cellRenderer. */
  229. public final static String CELL_RENDERER_PROPERTY = "cellRenderer";
  230. /** Bound property name for treeModel. */
  231. public final static String TREE_MODEL_PROPERTY = "treeModel";
  232. /** Bound property name for rootVisible. */
  233. public final static String ROOT_VISIBLE_PROPERTY = "rootVisible";
  234. /** Bound property name for showsRootHandles. */
  235. public final static String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
  236. /** Bound property name for rowHeight. */
  237. public final static String ROW_HEIGHT_PROPERTY = "rowHeight";
  238. /** Bound property name for cellEditor. */
  239. public final static String CELL_EDITOR_PROPERTY = "cellEditor";
  240. /** Bound property name for editable. */
  241. public final static String EDITABLE_PROPERTY = "editable";
  242. /** Bound property name for largeModel. */
  243. public final static String LARGE_MODEL_PROPERTY = "largeModel";
  244. /** Bound property name for selectionModel. */
  245. public final static String SELECTION_MODEL_PROPERTY = "selectionModel";
  246. /** Bound property name for visibleRowCount. */
  247. public final static String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
  248. /** Bound property name for messagesStopCellEditing. */
  249. public final static String INVOKES_STOP_CELL_EDITING_PROPERTY = "messagesStopCellEditing";
  250. /** Bound property name for scrollsOnExpand. */
  251. public final static String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand";
  252. /** Bound property name for toggleClickCount. */
  253. //public final static String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount";
  254. /**
  255. * Creates and returns a sample TreeModel. Used primarily for beanbuilders.
  256. * to show something interesting.
  257. *
  258. * @return the default TreeModel
  259. */
  260. protected static TreeModel getDefaultTreeModel() {
  261. DefaultMutableTreeNode root = new DefaultMutableTreeNode("JTree");
  262. DefaultMutableTreeNode parent;
  263. parent = new DefaultMutableTreeNode("colors");
  264. root.add(parent);
  265. parent.add(new DefaultMutableTreeNode("blue"));
  266. parent.add(new DefaultMutableTreeNode("violet"));
  267. parent.add(new DefaultMutableTreeNode("red"));
  268. parent.add(new DefaultMutableTreeNode("yellow"));
  269. parent = new DefaultMutableTreeNode("sports");
  270. root.add(parent);
  271. parent.add(new DefaultMutableTreeNode("basketball"));
  272. parent.add(new DefaultMutableTreeNode("soccer"));
  273. parent.add(new DefaultMutableTreeNode("football"));
  274. parent.add(new DefaultMutableTreeNode("hockey"));
  275. parent = new DefaultMutableTreeNode("food");
  276. root.add(parent);
  277. parent.add(new DefaultMutableTreeNode("hot dogs"));
  278. parent.add(new DefaultMutableTreeNode("pizza"));
  279. parent.add(new DefaultMutableTreeNode("ravioli"));
  280. parent.add(new DefaultMutableTreeNode("bananas"));
  281. return new DefaultTreeModel(root);
  282. }
  283. /**
  284. * Returns a TreeModel wrapping the specified object. If the object
  285. * is:<ul>
  286. * <li>an array of Objects,
  287. * <li>a Hashtable, or
  288. * <li>a Vector
  289. * </ul>then a new root node is created with each of the incoming
  290. * objects as children. Otherwise, a new root is created with the
  291. * specified object as its value.
  292. *
  293. * @param value the Object used as the foundation for the TreeModel
  294. * @return a TreeModel wrapping the specified object
  295. */
  296. protected static TreeModel createTreeModel(Object value) {
  297. DefaultMutableTreeNode root;
  298. if((value instanceof Object[]) || (value instanceof Hashtable) ||
  299. (value instanceof Vector)) {
  300. root = new DefaultMutableTreeNode("root");
  301. DynamicUtilTreeNode.createChildren(root, value);
  302. }
  303. else {
  304. root = new DynamicUtilTreeNode("root", value);
  305. }
  306. return new DefaultTreeModel(root, false);
  307. }
  308. /**
  309. * Returns a JTree with a sample model.
  310. * The default model used by the tree defines a leaf node as any node without
  311. * children.
  312. *
  313. * @return a JTree with the default model, which defines a leaf node
  314. * as any node without children.
  315. * @see DefaultTreeModel#asksAllowsChildren
  316. */
  317. public JTree() {
  318. this(getDefaultTreeModel());
  319. }
  320. /**
  321. * Returns a JTree with each element of the specified array as the
  322. * child of a new root node which is not displayed.
  323. * By default, the tree defines a leaf node as any node without
  324. * children.
  325. *
  326. * @param value an array of Objects
  327. * @return a JTree with the contents of the array as children of
  328. * the root node
  329. * @see DefaultTreeModel#asksAllowsChildren
  330. */
  331. public JTree(Object[] value) {
  332. this(createTreeModel(value));
  333. this.setRootVisible(false);
  334. this.setShowsRootHandles(true);
  335. }
  336. /**
  337. * Returns a JTree with each element of the specified Vector as the
  338. * child of a new root node which is not displayed. By default, the
  339. * tree defines a leaf node as any node without children.
  340. *
  341. * @param value a Vector
  342. * @return a JTree with the contents of the Vector as children of
  343. * the root node
  344. * @see DefaultTreeModel#asksAllowsChildren
  345. */
  346. public JTree(Vector value) {
  347. this(createTreeModel(value));
  348. this.setRootVisible(false);
  349. this.setShowsRootHandles(true);
  350. }
  351. /**
  352. * Returns a JTree created from a Hashtable which does not display
  353. * the root. Each value-half of the key/value pairs in the HashTable
  354. * becomes a child of the new root node. By default, the tree defines
  355. * a leaf node as any node without children.
  356. *
  357. * @param value a Hashtable
  358. * @return a JTree with the contents of the Hashtable as children of
  359. * the root node
  360. * @see DefaultTreeModel#asksAllowsChildren
  361. */
  362. public JTree(Hashtable value) {
  363. this(createTreeModel(value));
  364. this.setRootVisible(false);
  365. this.setShowsRootHandles(true);
  366. }
  367. /**
  368. * Returns a JTree with the specified TreeNode as its root, which
  369. * displays the root node. By default, the tree defines a leaf node as any node
  370. * without children.
  371. *
  372. * @param root a TreeNode object
  373. * @return a JTree with the specified root node
  374. * @see DefaultTreeModel#asksAllowsChildren
  375. */
  376. public JTree(TreeNode root) {
  377. this(root, false);
  378. }
  379. /**
  380. * Returns a JTree with the specified TreeNode as its root, which
  381. * displays the root node and which decides whether a node is a
  382. * leaf node in the specified manner.
  383. *
  384. * @param root a TreeNode object
  385. * @param asksAllowsChildren if false, any node without children is a
  386. * leaf node. If true, only nodes that do not allow
  387. * children are leaf nodes.
  388. * @return a JTree with the specified root node
  389. * @see DefaultTreeModel#asksAllowsChildren
  390. */
  391. public JTree(TreeNode root, boolean asksAllowsChildren) {
  392. this(new DefaultTreeModel(root, asksAllowsChildren));
  393. }
  394. /**
  395. * Returns an instance of JTree which displays the root node
  396. * -- the tree is created using the specified data model.
  397. *
  398. * @param newModel the TreeModel to use as the data model
  399. * @return a JTree based on the TreeModel
  400. */
  401. public JTree(TreeModel newModel) {
  402. super();
  403. expandedStack = new Stack();
  404. toggleClickCount = 2;
  405. expandedState = new Hashtable();
  406. setLayout(null);
  407. rowHeight = 16;
  408. visibleRowCount = 20;
  409. rootVisible = true;
  410. selectionModel = new DefaultTreeSelectionModel();
  411. cellRenderer = null;
  412. scrollsOnExpand = true;
  413. setOpaque(true);
  414. updateUI();
  415. setModel(newModel);
  416. }
  417. /**
  418. * Returns the L&F object that renders this component.
  419. *
  420. * @return the TreeUI object that renders this component
  421. */
  422. public TreeUI getUI() {
  423. return (TreeUI)ui;
  424. }
  425. /**
  426. * Sets the L&F object that renders this component.
  427. *
  428. * @param ui the TreeUI L&F object
  429. * @see UIDefaults#getUI
  430. */
  431. public void setUI(TreeUI ui) {
  432. if ((TreeUI)this.ui != ui) {
  433. super.setUI(ui);
  434. repaint();
  435. }
  436. }
  437. /**
  438. * Notification from the UIManager that the L&F has changed.
  439. * Replaces the current UI object with the latest version from the
  440. * UIManager.
  441. *
  442. * @see JComponent#updateUI
  443. */
  444. public void updateUI() {
  445. setUI((TreeUI)UIManager.getUI(this));
  446. invalidate();
  447. }
  448. /**
  449. * Returns the name of the L&F class that renders this component.
  450. *
  451. * @return "TreeUI"
  452. * @see JComponent#getUIClassID
  453. * @see UIDefaults#getUI
  454. */
  455. public String getUIClassID() {
  456. return uiClassID;
  457. }
  458. /**
  459. * Returns the current TreeCellRenderer that is rendering each cell.
  460. *
  461. * @return the TreeCellRenderer that is rendering each cell
  462. */
  463. public TreeCellRenderer getCellRenderer() {
  464. return cellRenderer;
  465. }
  466. /**
  467. * Sets the TreeCellRenderer that will be used to draw each cell.
  468. *
  469. * @param x the TreeCellRenderer that is to render each cell
  470. * @beaninfo
  471. * bound: true
  472. * description: The TreeCellRenderer that will be used to draw
  473. * each cell.
  474. */
  475. public void setCellRenderer(TreeCellRenderer x) {
  476. TreeCellRenderer oldValue = cellRenderer;
  477. cellRenderer = x;
  478. firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, cellRenderer);
  479. invalidate();
  480. }
  481. /**
  482. * Determines whether the tree is editable. Fires a property
  483. * change event if the new setting is different from the existing
  484. * setting.
  485. *
  486. * @param flag a boolean value, true if the tree is editable
  487. * @beaninfo
  488. * bound: true
  489. * description: Whether the tree is editable.
  490. */
  491. public void setEditable(boolean flag) {
  492. boolean oldValue = this.editable;
  493. this.editable = flag;
  494. firePropertyChange(EDITABLE_PROPERTY, oldValue, flag);
  495. if (accessibleContext != null) {
  496. accessibleContext.firePropertyChange(
  497. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  498. (oldValue ? AccessibleState.EDITABLE : null),
  499. (flag ? AccessibleState.EDITABLE : null));
  500. }
  501. }
  502. /**
  503. * Returns true if the tree is editable.
  504. *
  505. * @return true if the tree is editable.
  506. */
  507. public boolean isEditable() {
  508. return editable;
  509. }
  510. /**
  511. * Sets the cell editor. A null value implies that the
  512. * tree cannot be edited. If this represents a change in the
  513. * cellEditor, the propertyChange method is invoked on all
  514. * listeners.
  515. *
  516. * @param cellEditor the TreeCellEditor to use
  517. * @beaninfo
  518. * bound: true
  519. * description: The cell editor. A null value implies the tree
  520. * cannot be edited.
  521. */
  522. public void setCellEditor(TreeCellEditor cellEditor) {
  523. TreeCellEditor oldEditor = this.cellEditor;
  524. this.cellEditor = cellEditor;
  525. firePropertyChange(CELL_EDITOR_PROPERTY, oldEditor, cellEditor);
  526. invalidate();
  527. }
  528. /**
  529. * Returns the editor used to edit entries in the tree.
  530. *
  531. * @return the TreeCellEditor in use, or null if the tree cannot
  532. * be edited
  533. */
  534. public TreeCellEditor getCellEditor() {
  535. return cellEditor;
  536. }
  537. /**
  538. * Returns the TreeModel that is providing the data.
  539. *
  540. * @return the TreeModel that is providing the data
  541. */
  542. public TreeModel getModel() {
  543. return treeModel;
  544. }
  545. /**
  546. * Sets the TreeModel that will provide the data.
  547. *
  548. * @param newModel the TreeModel that is to provide the data
  549. * @beaninfo
  550. * bound: true
  551. * description: The TreeModel that will provide the data.
  552. */
  553. public void setModel(TreeModel newModel) {
  554. TreeModel oldModel = treeModel;
  555. if(treeModel != null && treeModelListener != null)
  556. treeModel.removeTreeModelListener(treeModelListener);
  557. if (accessibleContext != null) {
  558. if (treeModel != null) {
  559. treeModel.removeTreeModelListener((TreeModelListener)accessibleContext);
  560. }
  561. if (newModel != null) {
  562. newModel.addTreeModelListener((TreeModelListener)accessibleContext);
  563. }
  564. }
  565. treeModel = newModel;
  566. clearToggledPaths();
  567. if(treeModel != null) {
  568. if(treeModelListener == null)
  569. treeModelListener = createTreeModelListener();
  570. if(treeModelListener != null)
  571. treeModel.addTreeModelListener(treeModelListener);
  572. // Mark the root as expanded, if it isn't a leaf.
  573. if(!treeModel.isLeaf(treeModel.getRoot()))
  574. expandedState.put(new TreePath(treeModel.getRoot()),
  575. Boolean.TRUE);
  576. }
  577. firePropertyChange(TREE_MODEL_PROPERTY, oldModel, treeModel);
  578. invalidate();
  579. }
  580. /**
  581. * Returns true if the root node of the tree is displayed.
  582. *
  583. * @return true if the root node of the tree is displayed
  584. * @see #rootVisible
  585. */
  586. public boolean isRootVisible() {
  587. return rootVisible;
  588. }
  589. /**
  590. * Determines whether or not the root node from
  591. * the TreeModel is visible.
  592. *
  593. * @param rootVisible true if the root node of the tree is to be displayed
  594. * @see #rootVisible
  595. * @beaninfo
  596. * bound: true
  597. * description: Whether or not the root node
  598. * from the TreeModel is visible.
  599. */
  600. public void setRootVisible(boolean rootVisible) {
  601. boolean oldValue = this.rootVisible;
  602. this.rootVisible = rootVisible;
  603. firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, this.rootVisible);
  604. if (accessibleContext != null) {
  605. ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  606. }
  607. }
  608. /**
  609. * Determines whether the node handles are to be displayed.
  610. *
  611. * @param newValue true if root handles are to be displayed
  612. * @see #showsRootHandles
  613. * @beaninfo
  614. * bound: true
  615. * description: Whether the node handles are to be
  616. * displayed.
  617. */
  618. public void setShowsRootHandles(boolean newValue) {
  619. boolean oldValue = showsRootHandles;
  620. TreeModel model = getModel();
  621. showsRootHandles = newValue;
  622. firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue,
  623. showsRootHandles);
  624. if (accessibleContext != null) {
  625. ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  626. }
  627. // Make SURE the root is expanded
  628. if(model != null) {
  629. expandPath(new TreePath(model.getRoot()));
  630. }
  631. invalidate();
  632. }
  633. /**
  634. * Returns true if handles for the root nodes are displayed.
  635. *
  636. * @return true if root handles are displayed
  637. * @see #showsRootHandles
  638. */
  639. public boolean getShowsRootHandles()
  640. {
  641. return showsRootHandles;
  642. }
  643. /**
  644. * Sets the height of each cell. If the specified value
  645. * is less than or equal to zero the current cell renderer is
  646. * queried for each row's height.
  647. *
  648. * @param rowHeight the height of each cell, in pixels
  649. * @beaninfo
  650. * bound: true
  651. * description: The height of each cell.
  652. */
  653. public void setRowHeight(int rowHeight)
  654. {
  655. int oldValue = this.rowHeight;
  656. this.rowHeight = rowHeight;
  657. firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, this.rowHeight);
  658. invalidate();
  659. }
  660. /**
  661. * Returns the height of each row. If the returned value is less than
  662. * or equal to 0 the height for each row is determined by the
  663. * renderer.
  664. *
  665. * @param the height of each cell, in pixels. Zero or negative if the
  666. * height of each row is determined by the tree cell renderer
  667. */
  668. public int getRowHeight()
  669. {
  670. return rowHeight;
  671. }
  672. /**
  673. * Returns true if the height of each display row is a fixed size.
  674. *
  675. * @return true if the height of each row is a fixed size
  676. */
  677. public boolean isFixedRowHeight()
  678. {
  679. return (rowHeight > 0);
  680. }
  681. /**
  682. * Specifies whether the UI should use a large model.
  683. * (Not all UIs will implement this.) Fires a property change
  684. * for the LARGE_MODEL_PROPERTY.
  685. *
  686. * @param newValue true to suggest a large model to the UI
  687. * @see #largeModel
  688. * @beaninfo
  689. * bound: true
  690. * description: Whether the UI should use a
  691. * large model.
  692. */
  693. public void setLargeModel(boolean newValue) {
  694. boolean oldValue = largeModel;
  695. largeModel = newValue;
  696. firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, newValue);
  697. }
  698. /**
  699. * Returns true if the tree is configured for a large model.
  700. *
  701. * @return true if a large model is suggested
  702. * @see #largeModel
  703. */
  704. public boolean isLargeModel() {
  705. return largeModel;
  706. }
  707. /**
  708. * Determines what happens when editing is interrupted by selecting
  709. * another node in the tree, a change in the tree's data, or by some
  710. * other means. Setting this property to <code>true</code> causes the
  711. * changes to be automatically saved when editing is interrupted.
  712. * <p>
  713. * Fires a property change for the INVOKES_STOP_CELL_EDITING_PROPERTY.
  714. *
  715. * @param newValue true means that stopCellEditing is invoked when
  716. * editing is interruped, and data is saved. False means that
  717. * cancelCellEditing is invoked, and changes are lost.
  718. * @beaninfo
  719. * bound: true
  720. * description: Determines what happens when editing is interrupted,
  721. * selecting another node in the tree, a change in the
  722. * tree's data, or some other means.
  723. */
  724. public void setInvokesStopCellEditing(boolean newValue) {
  725. boolean oldValue = invokesStopCellEditing;
  726. invokesStopCellEditing = newValue;
  727. firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, oldValue,
  728. newValue);
  729. }
  730. /**
  731. * Returns the indicator that tells what happens when editing is
  732. * interrupted.
  733. *
  734. * @return the indicator that tells what happens when editing is
  735. * interrupted
  736. * @see #setInvokesStopCellEditing
  737. */
  738. public boolean getInvokesStopCellEditing() {
  739. return invokesStopCellEditing;
  740. }
  741. /**
  742. * Determines whether or not when a node is expanded, as many of
  743. * the descendants are scrolled to be inside the viewport as
  744. * possible. The default is true.
  745. */
  746. public void setScrollsOnExpand(boolean newValue) {
  747. boolean oldValue = scrollsOnExpand;
  748. scrollsOnExpand = newValue;
  749. firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue,
  750. newValue);
  751. }
  752. /**
  753. * Returns true if the tree scrolls to show previously hidden children.
  754. * @return true if when a node is expanded as many of the descendants
  755. * as possible are scrolled to be visible.
  756. */
  757. public boolean getScrollsOnExpand() {
  758. return scrollsOnExpand;
  759. }
  760. // NOTE: This property will be enabled in a future release.
  761. /**
  762. * Sets the number of mouse clicks before a node will expand or close.
  763. * The default is two.
  764. */
  765. /*
  766. public void setToggleClickCount(int clickCount) {
  767. int oldCount = toggleClickCount;
  768. toggleClickCount = clickCount;
  769. firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldCount,
  770. clickCount);
  771. }
  772. */
  773. /**
  774. * Returns the number of mouse clicks needed to expand or close a node.
  775. * @return number of mouse clicks before node is expanded.
  776. */
  777. /*
  778. public int getToggleClickCount() {
  779. return toggleClickCount;
  780. }
  781. */
  782. /**
  783. * Returns <code>isEditable</code>. This is invoked from the UI before
  784. * editing begins to insure that the given path can be edited. This
  785. * is provided as an entry point for subclassers to add filtered
  786. * editing without having to resort to creating a new editor.
  787. *
  788. * @return true if every parent node and the node itself is editabled
  789. * @see #isEditable
  790. */
  791. public boolean isPathEditable(TreePath path) {
  792. return isEditable();
  793. }
  794. /**
  795. * Overrides JComponent's getToolTipText method in order to allow
  796. * renderer's tips to be used if it has text set.
  797. * <p>
  798. * NOTE: For JTree to properly display tooltips of its renderers
  799. * JTree must be a registered component with the ToolTipManager.
  800. * This can be done by invoking
  801. * <code>ToolTipManager.sharedInstance().registerComponent(tree)</code>.
  802. * This is not done automaticly!
  803. *
  804. * @param event the MouseEvent that initiated the ToolTip display
  805. */
  806. public String getToolTipText(MouseEvent event) {
  807. if(event != null) {
  808. Point p = event.getPoint();
  809. int selRow = getRowForLocation(p.x, p.y);
  810. TreeCellRenderer r = getCellRenderer();
  811. if(selRow != -1 && r != null) {
  812. TreePath path = getPathForRow(selRow);
  813. Object lastPath = path.getLastPathComponent();
  814. Component rComponent = r.getTreeCellRendererComponent
  815. (this, lastPath, isRowSelected(selRow),
  816. isExpanded(selRow), getModel().isLeaf(lastPath), selRow,
  817. true);
  818. if(rComponent instanceof JComponent) {
  819. MouseEvent newEvent;
  820. Rectangle pathBounds = getPathBounds(path);
  821. p.translate(-pathBounds.x, -pathBounds.y);
  822. newEvent = new MouseEvent(rComponent, event.getID(),
  823. event.getWhen(),
  824. event.getModifiers(),
  825. p.x, p.y, event.getClickCount(),
  826. event.isPopupTrigger());
  827. return ((JComponent)rComponent).getToolTipText(newEvent);
  828. }
  829. }
  830. }
  831. return null;
  832. }
  833. /**
  834. * Called by the renderers to convert the specified value to
  835. * text. This implementation returns value.toString(), ignoring
  836. * all other arguments. To control the conversion, subclass this
  837. * method and use any of the arguments you need.
  838. *
  839. * @param value the Object to convert to text
  840. * @param selected true if the node is selected
  841. * @param expanded true if the node is expanded
  842. * @param leaf true if the node is a leaf node
  843. * @param row an int specifying the node's display row, where 0 is
  844. * the first row in the display
  845. * @param hasFocus true if the node has the focus
  846. * @return the String representation of the node's value
  847. */
  848. public String convertValueToText(Object value, boolean selected,
  849. boolean expanded, boolean leaf, int row,
  850. boolean hasFocus) {
  851. if(value != null)
  852. return value.toString();
  853. return "";
  854. }
  855. //
  856. // The following are convenience methods that get forwarded to the
  857. // current TreeUI.
  858. //
  859. /**
  860. * Returns the number of rows that are currently being displayed.
  861. *
  862. * @return the number of rows that are being displayed
  863. */
  864. public int getRowCount() {
  865. TreeUI tree = getUI();
  866. if(tree != null)
  867. return tree.getRowCount(this);
  868. return 0;
  869. }
  870. /**
  871. * Selects the node identified by the specified path. If any
  872. * component of the path is hidden (under a collapsed node), it is
  873. * exposed (made viewable).
  874. *
  875. * @param path the TreePath specifying the node to select
  876. */
  877. public void setSelectionPath(TreePath path) {
  878. makeVisible(path);
  879. getSelectionModel().setSelectionPath(path);
  880. }
  881. /**
  882. * Selects the nodes identified by the specified array of paths.
  883. * If any component in any of the paths is hidden (under a collapsed
  884. * node), it is exposed (made viewable).
  885. *
  886. * @param paths an array of TreePath objects that specifies the nodes
  887. * to select
  888. */
  889. public void setSelectionPaths(TreePath[] paths) {
  890. if(paths != null) {
  891. for(int counter = paths.length - 1; counter >= 0; counter--)
  892. makeVisible(paths[counter]);
  893. }
  894. getSelectionModel().setSelectionPaths(paths);
  895. }
  896. /**
  897. * Selects the node at the specified row in the display.
  898. *
  899. * @param row the row to select, where 0 is the first row in
  900. * the display
  901. */
  902. public void setSelectionRow(int row) {
  903. int[] rows = { row };
  904. setSelectionRows(rows);
  905. }
  906. /**
  907. * Selects the nodes corresponding to each of the specified rows
  908. * in the display. If a particular element of <code>rows</code> is
  909. * < 0 or >= getRowCount, it will be ignored. If none of the elements
  910. * in <code>rows</code> are valid rows, the selection will
  911. * be cleared. That is it will be as if <code>clearSelection</code>
  912. * was invoked.
  913. *
  914. * @param rows an array of ints specifying the rows to select,
  915. * where 0 indicates the first row in the display
  916. */
  917. public void setSelectionRows(int[] rows) {
  918. TreeUI ui = getUI();
  919. if(ui != null && rows != null) {
  920. int numRows = rows.length;
  921. TreePath[] paths = new TreePath[numRows];
  922. for(int counter = 0; counter < numRows; counter++)
  923. paths[counter] = ui.getPathForRow(this, rows[counter]);
  924. setSelectionPaths(paths);
  925. }
  926. }
  927. /**
  928. * Adds the node identified by the specified TreePath to the current
  929. * selection. If any component of the path isn't viewable, it is
  930. * made viewable.
  931. *
  932. * @param path the TreePath to add
  933. */
  934. public void addSelectionPath(TreePath path) {
  935. makeVisible(path);
  936. getSelectionModel().addSelectionPath(path);
  937. }
  938. /**
  939. * Adds each path in the array of paths to the current selection. If
  940. * any component of any of the paths isn't viewable, it is
  941. * made viewable.
  942. *
  943. * @param paths an array of TreePath objects that specifies the nodes
  944. * to add
  945. */
  946. public void addSelectionPaths(TreePath[] paths) {
  947. if(paths != null) {
  948. for(int counter = paths.length - 1; counter >= 0; counter--)
  949. makeVisible(paths[counter]);
  950. }
  951. getSelectionModel().addSelectionPaths(paths);
  952. }
  953. /**
  954. * Adds the path at the specified row to the current selection.
  955. *
  956. * @param row an int specifying the row of the node to add,
  957. * where 0 is the first row in the display
  958. */
  959. public void addSelectionRow(int row) {
  960. int[] rows = { row };
  961. addSelectionRows(rows);
  962. }
  963. /**
  964. * Adds the paths at each of the specified rows to the current selection.
  965. *
  966. * @param rows an array of ints specifying the rows to add,
  967. * where 0 indicates the first row in the display
  968. */
  969. public void addSelectionRows(int[] rows) {
  970. TreeUI ui = getUI();
  971. if(ui != null && rows != null) {
  972. int numRows = rows.length;
  973. TreePath[] paths = new TreePath[numRows];
  974. for(int counter = 0; counter < numRows; counter++)
  975. paths[counter] = ui.getPathForRow(this, rows[counter]);
  976. addSelectionPaths(paths);
  977. }
  978. }
  979. /**
  980. * Returns the last path component in the first node of the current
  981. * selection.
  982. *
  983. * @return the last Object in the first selected node's TreePath,
  984. * or null if nothing is selected
  985. * @see TreePath#getLastPathComponent
  986. */
  987. public Object getLastSelectedPathComponent() {
  988. TreePath selPath = getSelectionModel().getSelectionPath();
  989. if(selPath != null)
  990. return selPath.getLastPathComponent();
  991. return null;
  992. }
  993. /**
  994. * Returns the path to the first selected node.
  995. *
  996. * @return the TreePath for the first selected node, or null if
  997. * nothing is currently selected
  998. */
  999. public TreePath getSelectionPath() {
  1000. return getSelectionModel().getSelectionPath();
  1001. }
  1002. /**
  1003. * Returns the paths of all selected values.
  1004. *
  1005. * @return an array of TreePath objects indicating the selected
  1006. * nodes, or null if nothing is currently selected.
  1007. */
  1008. public TreePath[] getSelectionPaths() {
  1009. return getSelectionModel().getSelectionPaths();
  1010. }
  1011. /**
  1012. * Returns all of the currently selected rows. This method is simply
  1013. * forwarded to the TreeSelectionModel. If nothing is selected null
  1014. * or an empty array with be returned, based on the TreeSelectionModel
  1015. * implementation.
  1016. *
  1017. * @return an array of ints that identifies all currently selected rows
  1018. * where 0 is the first row in the display
  1019. */
  1020. public int[] getSelectionRows() {
  1021. return getSelectionModel().getSelectionRows();
  1022. }
  1023. /**
  1024. * Returns the number of nodes selected.
  1025. *
  1026. * @return the number of nodes selected
  1027. */
  1028. public int getSelectionCount() {
  1029. return selectionModel.getSelectionCount();
  1030. }
  1031. /**
  1032. * Gets the first selected row.
  1033. *
  1034. * @return an int designating the first selected row, where 0 is the
  1035. * first row in the display
  1036. */
  1037. public int getMinSelectionRow() {
  1038. return getSelectionModel().getMinSelectionRow();
  1039. }
  1040. /**
  1041. * Gets the last selected row.
  1042. *
  1043. * @return an int designating the last selected row, where 0 is the
  1044. * first row in the display
  1045. */
  1046. public int getMaxSelectionRow() {
  1047. return getSelectionModel().getMaxSelectionRow();
  1048. }
  1049. /**
  1050. * Returns the row index of the last node added to the selection.
  1051. *
  1052. * @return an int giving the row index of the last node added to the
  1053. * selection, where 0 is the first row in the display
  1054. */
  1055. public int getLeadSelectionRow() {
  1056. return getSelectionModel().getLeadSelectionRow();
  1057. }
  1058. /**
  1059. * Returns the path of the last node added to the selection.
  1060. *
  1061. * @return the TreePath of the last node added to the selection.
  1062. */
  1063. public TreePath getLeadSelectionPath() {
  1064. return getSelectionModel().getLeadSelectionPath();
  1065. }
  1066. /**
  1067. * Returns true if the item identified by the path is currently selected.
  1068. *
  1069. * @param path a TreePath identifying a node
  1070. * @return true if the node is selected
  1071. */
  1072. public boolean isPathSelected(TreePath path) {
  1073. return getSelectionModel().isPathSelected(path);
  1074. }
  1075. /**
  1076. * Returns true if the node identitifed by row is selected.
  1077. *
  1078. * @param row an int specifying a display row, where 0 is the first
  1079. * row in the display
  1080. * @return true if the node is selected
  1081. */
  1082. public boolean isRowSelected(int row) {
  1083. return getSelectionModel().isRowSelected(row);
  1084. }
  1085. /**
  1086. * Returns an Enumeration of the descendants of <code>path</code> that
  1087. * are currently expanded. If <code>path</code> is not currently
  1088. * expanded, this will return null. If you expand/collapse nodes while
  1089. * iterating over the returned Enumeration this may not return all
  1090. * the expanded paths, or may return paths that are no longer expanded.
  1091. */
  1092. public Enumeration getExpandedDescendants(TreePath parent) {
  1093. if(!isExpanded(parent))
  1094. return null;
  1095. Enumeration toggledPaths = expandedState.keys();
  1096. Vector elements = new Vector();
  1097. TreePath path;
  1098. Object value;
  1099. if(toggledPaths != null) {
  1100. while(toggledPaths.hasMoreElements()) {
  1101. path = (TreePath)toggledPaths.nextElement();
  1102. value = expandedState.get(path);
  1103. // Add the path if it is expanded, a descendant of parent,
  1104. // and it is visible (all parents expanded). This is rather
  1105. // expensive!
  1106. if(value != null && ((Boolean)value).booleanValue() &&
  1107. parent.isDescendant(path) && isVisible(path)) {
  1108. elements.addElement(path);
  1109. }
  1110. }
  1111. }
  1112. return elements.elements();
  1113. }
  1114. /**
  1115. * Returns true if the node identified by the path has ever been
  1116. * expanded.
  1117. */
  1118. public boolean hasBeenExpanded(TreePath path) {
  1119. return (path != null && expandedState.get(path) != null);
  1120. }
  1121. /**
  1122. * Returns true if the node identified by the path is currently expanded,
  1123. *
  1124. * @param path the TreePath specifying the node to check
  1125. * @return false if any of the nodes in the node's path are collapsed,
  1126. * true if all nodes in the path are expanded
  1127. */
  1128. public boolean isExpanded(TreePath path) {
  1129. if(path == null)
  1130. return false;
  1131. // Is this node expanded?
  1132. Object value = expandedState.get(path);
  1133. if(value == null || !((Boolean)value).booleanValue())
  1134. return false;
  1135. // It is, make sure its parent is also expanded.
  1136. TreePath parentPath = path.getParentPath();
  1137. if(parentPath != null)
  1138. return isExpanded(parentPath);
  1139. return true;
  1140. }
  1141. /**
  1142. * Returns true if the node at the specified display row is currently
  1143. * expanded.
  1144. *
  1145. * @param row the row to check, where 0 is the first row in the
  1146. * display
  1147. * @return true if the node is currently expanded, otherwise false
  1148. */
  1149. public boolean isExpanded(int row) {
  1150. TreeUI tree = getUI();
  1151. if(tree != null) {
  1152. TreePath path = tree.getPathForRow(this, row);
  1153. if(path != null)
  1154. return isExpanded(path);
  1155. }
  1156. return false;
  1157. }
  1158. /**
  1159. * Returns true if the value identified by path is currently collapsed,
  1160. * this will return false if any of the values in path are currently
  1161. * not being displayed.
  1162. *
  1163. * @param path the TreePath to check
  1164. * @return true if any of the nodes in the node's path are collapsed,
  1165. * false if all nodes in the path are expanded
  1166. */
  1167. public boolean isCollapsed(TreePath path) {
  1168. return !isExpanded(path);
  1169. }
  1170. /**
  1171. * Returns true if the node at the specified display row is collapsed.
  1172. *
  1173. * @param row the row to check, where 0 is the first row in the
  1174. * display
  1175. * @return true if the node is currently collapsed, otherwise false
  1176. */
  1177. public boolean isCollapsed(int row) {
  1178. return !isExpanded(row);
  1179. }
  1180. /**
  1181. * Ensures that the node identified by path is currently viewable.
  1182. *
  1183. * @param path the TreePath to make visible
  1184. */
  1185. public void makeVisible(TreePath path) {
  1186. if(path != null) {
  1187. TreePath parentPath = path.getParentPath();
  1188. if(parentPath != null) {
  1189. expandPath(parentPath);
  1190. }
  1191. }
  1192. }
  1193. /**
  1194. * Returns true if the value identified by path is currently viewable,
  1195. * which means it is either the root or all of its parents are exapnded ,
  1196. * Otherwise, this method returns false.
  1197. *
  1198. * @return true if the node is viewable, otherwise false
  1199. */
  1200. public boolean isVisible(TreePath path) {
  1201. if(path != null) {
  1202. TreePath parentPath = path.getParentPath();
  1203. if(parentPath != null)
  1204. return isExpanded(parentPath);
  1205. // Root.
  1206. return true;
  1207. }
  1208. return false;
  1209. }
  1210. /**
  1211. * Returns the Rectangle that the specified node will be drawn
  1212. * into. Returns null if any component in the path is hidden
  1213. * (under a collapsed parent).
  1214. * <p>
  1215. * Note:<br>
  1216. * This method returns a valid rectangle, even if the specified
  1217. * node is not currently displayed.
  1218. *
  1219. * @param path the TreePath identifying the node
  1220. * @return the Rectangle the node is drawn in, or null
  1221. */
  1222. public Rectangle getPathBounds(TreePath path) {
  1223. TreeUI tree = getUI();
  1224. if(tree != null)
  1225. return tree.getPathBounds(this, path);
  1226. return null;
  1227. }
  1228. /**
  1229. * Returns the Rectangle that the node at the specified row is
  1230. * drawn in.
  1231. *
  1232. * @param row the row to be drawn, where 0 is the first row in the
  1233. * display
  1234. * @return the Rectangle the node is drawn in
  1235. */
  1236. public Rectangle getRowBounds(int row) {
  1237. TreePath path = getPathForRow(row);
  1238. return getPathBounds(getPathForRow(row));
  1239. }
  1240. /**
  1241. * Makes sure all the path components in path are expanded (except
  1242. * for the last path component) and scrolls so that the
  1243. * node identified by the path is displayed. Only works when this
  1244. * JTree is contained in a JSrollPane.
  1245. *
  1246. * @param path the TreePath identifying the node to bring into view
  1247. */
  1248. public void scrollPathToVisible(TreePath path) {
  1249. if(path != null) {
  1250. makeVisible(path);
  1251. Rectangle bounds = getPathBounds(path);
  1252. if(bounds != null) {
  1253. scrollRectToVisible(bounds);
  1254. if (accessibleContext != null) {
  1255. ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
  1256. }
  1257. }
  1258. }
  1259. }
  1260. /**
  1261. * Scrolls the item identified by row until it is displayed. The minimum
  1262. * of amount of scrolling necessary to bring the row into view
  1263. * is performed. Only works when this JTree is contained in a
  1264. * JSrollPane.
  1265. *
  1266. * @param row an int specifying the row to scroll, where 0 is the
  1267. * first row in the display
  1268. */
  1269. public void scrollRowToVisible(int row) {
  1270. scrollPathToVisible(getPathForRow(row));
  1271. }
  1272. /**
  1273. * Returns the path for the specified row.
  1274. * <!-->If row is not visible null is returned.<-->
  1275. *
  1276. * @param row an int specifying a row
  1277. * @return the TreePath to the specified node, null if
  1278. * row < 0 or row > getRowCount()
  1279. */
  1280. public TreePath getPathForRow(int row) {
  1281. TreeUI tree = getUI();
  1282. if(tree != null)
  1283. return tree.getPathForRow(this, row);
  1284. return null;
  1285. }
  1286. /**
  1287. * Returns the row that displays the node identified by the specified
  1288. * path.
  1289. *
  1290. * @param path the TreePath identifying a node
  1291. * @return an int specifying the display row, where 0 is the first
  1292. * row in the display, or -1 if any of the elements in path
  1293. * are hidden under a collapsed parent.
  1294. */
  1295. public int getRowForPath(TreePath path) {
  1296. TreeUI tree = getUI();
  1297. if(tree != null)
  1298. return tree.getRowForPath(this, path);
  1299. return -1;
  1300. }
  1301. /**
  1302. * Ensures that the node identified by the specified path is
  1303. * expanded and viewable.
  1304. *
  1305. * @param path the TreePath identifying a node
  1306. */
  1307. public void expandPath(TreePath path) {
  1308. // Only expand if not leaf!
  1309. TreeModel model = getModel();
  1310. if(path != null && model != null &&
  1311. !model.isLeaf(path.getLastPathComponent())) {
  1312. setExpandedState(path, true);
  1313. }
  1314. }
  1315. /**
  1316. * Ensures that the node in the specified row is expanded and
  1317. * viewable. <p> If <code>row</code> is < 0 or >= getRowCount this
  1318. * will have no effect.
  1319. *
  1320. * @param row an int specifying a display row, where 0 is the
  1321. * first row in the display
  1322. */
  1323. public void expandRow(int row) {
  1324. expandPath(getPathForRow(row));
  1325. }
  1326. /**
  1327. * Ensures that the node identified by the specified path is
  1328. * collapsed and viewable.
  1329. *
  1330. * @param path the TreePath identifying a node
  1331. */
  1332. public void collapsePath(TreePath path) {
  1333. setExpandedState(path, false);
  1334. }
  1335. /**
  1336. * Ensures that the node in the specified row is collapsed.
  1337. * <p> If <code>row</code> is < 0 or >= getRowCount this
  1338. * will have no effect.
  1339. *
  1340. * @param row an int specifying a display row, where 0 is the
  1341. * first row in the display
  1342. */
  1343. public void collapseRow(int row) {
  1344. collapsePath(getPathForRow(row));
  1345. }
  1346. /**
  1347. * Returns the path for the node at the specified location.
  1348. *
  1349. * @param x an int giving the number of pixels horizontally from
  1350. * the left edge of the display area, minus any left margin
  1351. * @param y an int giving the number of pixels vertically from
  1352. * the top of the display area, minus any top margin
  1353. * @return the TreePath for the node at that location
  1354. */
  1355. public TreePath getPathForLocation(int x, int y) {
  1356. TreePath closestPath = getClosestPathForLocation(x, y);
  1357. if(closestPath != null) {
  1358. Rectangle pathBounds = getPathBounds(closestPath);
  1359. if(x >= pathBounds.x && x < (pathBounds.x + pathBounds.width) &&
  1360. y >= pathBounds.y && y < (pathBounds.y + pathBounds.height))
  1361. return closestPath;
  1362. }
  1363. return null;
  1364. }
  1365. /**
  1366. * Returns the row for the specified location.
  1367. *
  1368. * @param x an int giving the number of pixels horizontally from
  1369. * the left edge of the display area, minus any left margin
  1370. * @param y an int giving the number of pixels vertically from
  1371. * the top of the display area, minus any top margin
  1372. * @return the row corresponding to the location, or -1 if the
  1373. * location is not within the bounds of a displayed cell
  1374. * @see #getClosestRowForLocation
  1375. */
  1376. public int getRowForLocation(int x, int y) {
  1377. return getRowForPath(getPathForLocation(x, y));
  1378. }
  1379. /**
  1380. * Returns the path to the node that is closest to x,y. If
  1381. * no nodes are currently viewable, or there is no model, returns
  1382. * null, otherwise it always returns a valid path. To test if
  1383. * the node is exactly at x, y, get the node's bounds and
  1384. * test x, y against that.
  1385. *
  1386. * @param x an int giving the number of pixels horizontally from
  1387. * the left edge of the display area, minus any left margin
  1388. * @param y an int giving the number of pixels vertically from
  1389. * the top of the display area, minus any top margin
  1390. * @return the TreePath for the node closest to that location,
  1391. * null if nothing is viewable or there is no model
  1392. *
  1393. * @see #getPathForLocation
  1394. * @see #getPathBounds
  1395. */
  1396. public TreePath getClosestPathForLocation(int x, int y) {
  1397. TreeUI tree = getUI();
  1398. if(tree != null)
  1399. return tree.getClosestPathForLocation(this, x, y);
  1400. return null;
  1401. }
  1402. /**
  1403. * Returns the row to the node that is closest to x,y. If no nodes
  1404. * are viewable or there is no model, returns -1. Otherwise,
  1405. * it always returns a valid row. To test if the returned object is
  1406. * exactly at x, y, get the bounds for the node at the returned
  1407. * row and test x, y against that.
  1408. *
  1409. * @param x an int giving the number of pixels horizontally from
  1410. * the left edge of the display area, minus any left margin
  1411. * @param y an int giving the number of pixels vertically from
  1412. * the top of the display area, minus any top margin
  1413. * @return the row closest to the location, -1 if nothing is
  1414. * viewable or there is no model
  1415. *
  1416. * @see #getRowForLocation
  1417. * @see #getRowBounds
  1418. */
  1419. public int getClosestRowForLocation(int x, int y) {
  1420. return getRowForPath(getClosestPathForLocation(x, y));
  1421. }
  1422. /**
  1423. * Returns true if the tree is being edited. The item that is being
  1424. * edited can be obtained using <code>getSelectionPath</code>.
  1425. *
  1426. * @return true if the user is currently editing