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