Source for javax.swing.plaf.basic.BasicTreeUI

   1: /* BasicTreeUI.java --
   2:  Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
   3: 
   4:  This file is part of GNU Classpath.
   5: 
   6:  GNU Classpath is free software; you can redistribute it and/or modify
   7:  it under the terms of the GNU General Public License as published by
   8:  the Free Software Foundation; either version 2, or (at your option)
   9:  any later version.
  10: 
  11:  GNU Classpath is distributed in the hope that it will be useful, but
  12:  WITHOUT ANY WARRANTY; without even the implied warranty of
  13:  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14:  General Public License for more details.
  15: 
  16:  You should have received a copy of the GNU General Public License
  17:  along with GNU Classpath; see the file COPYING.  If not, write to the
  18:  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19:  02110-1301 USA.
  20: 
  21:  Linking this library statically or dynamically with other modules is
  22:  making a combined work based on this library.  Thus, the terms and
  23:  conditions of the GNU General Public License cover the whole
  24:  combination.
  25: 
  26:  As a special exception, the copyright holders of this library give you
  27:  permission to link this library with independent modules to produce an
  28:  executable, regardless of the license terms of these independent
  29:  modules, and to copy and distribute the resulting executable under
  30:  terms of your choice, provided that you also meet, for each linked
  31:  independent module, the terms and conditions of the license of that
  32:  module.  An independent module is a module which is not derived from
  33:  or based on this library.  If you modify this library, you may extend
  34:  this exception to your version of the library, but you are not
  35:  obligated to do so.  If you do not wish to do so, delete this
  36:  exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import gnu.javax.swing.tree.GnuPath;
  42: 
  43: import java.awt.Color;
  44: import java.awt.Component;
  45: import java.awt.Container;
  46: import java.awt.Dimension;
  47: import java.awt.Graphics;
  48: import java.awt.Insets;
  49: import java.awt.Label;
  50: import java.awt.Point;
  51: import java.awt.Rectangle;
  52: import java.awt.event.ActionEvent;
  53: import java.awt.event.ActionListener;
  54: import java.awt.event.ComponentAdapter;
  55: import java.awt.event.ComponentEvent;
  56: import java.awt.event.ComponentListener;
  57: import java.awt.event.FocusEvent;
  58: import java.awt.event.FocusListener;
  59: import java.awt.event.InputEvent;
  60: import java.awt.event.KeyAdapter;
  61: import java.awt.event.KeyEvent;
  62: import java.awt.event.KeyListener;
  63: import java.awt.event.MouseAdapter;
  64: import java.awt.event.MouseEvent;
  65: import java.awt.event.MouseListener;
  66: import java.awt.event.MouseMotionListener;
  67: import java.beans.PropertyChangeEvent;
  68: import java.beans.PropertyChangeListener;
  69: import java.util.Enumeration;
  70: import java.util.Hashtable;
  71: 
  72: import javax.swing.AbstractAction;
  73: import javax.swing.Action;
  74: import javax.swing.ActionMap;
  75: import javax.swing.CellRendererPane;
  76: import javax.swing.Icon;
  77: import javax.swing.InputMap;
  78: import javax.swing.JComponent;
  79: import javax.swing.JScrollBar;
  80: import javax.swing.JScrollPane;
  81: import javax.swing.JTree;
  82: import javax.swing.LookAndFeel;
  83: import javax.swing.SwingUtilities;
  84: import javax.swing.Timer;
  85: import javax.swing.UIManager;
  86: import javax.swing.event.CellEditorListener;
  87: import javax.swing.event.ChangeEvent;
  88: import javax.swing.event.MouseInputListener;
  89: import javax.swing.event.TreeExpansionEvent;
  90: import javax.swing.event.TreeExpansionListener;
  91: import javax.swing.event.TreeModelEvent;
  92: import javax.swing.event.TreeModelListener;
  93: import javax.swing.event.TreeSelectionEvent;
  94: import javax.swing.event.TreeSelectionListener;
  95: import javax.swing.plaf.ActionMapUIResource;
  96: import javax.swing.plaf.ComponentUI;
  97: import javax.swing.plaf.TreeUI;
  98: import javax.swing.tree.AbstractLayoutCache;
  99: import javax.swing.tree.DefaultTreeCellEditor;
 100: import javax.swing.tree.DefaultTreeCellRenderer;
 101: import javax.swing.tree.TreeCellEditor;
 102: import javax.swing.tree.TreeCellRenderer;
 103: import javax.swing.tree.TreeModel;
 104: import javax.swing.tree.TreeNode;
 105: import javax.swing.tree.TreePath;
 106: import javax.swing.tree.TreeSelectionModel;
 107: import javax.swing.tree.VariableHeightLayoutCache;
 108: 
 109: /**
 110:  * A delegate providing the user interface for <code>JTree</code> according to
 111:  * the Basic look and feel.
 112:  * 
 113:  * @see javax.swing.JTree
 114:  * @author Lillian Angel (langel@redhat.com)
 115:  * @author Sascha Brawer (brawer@dandelis.ch)
 116:  * @author Audrius Meskauskas (audriusa@bioinformatics.org)
 117:  */
 118: public class BasicTreeUI
 119:   extends TreeUI
 120: {
 121:   /**
 122:    * The tree cell editing may be started by the single mouse click on the
 123:    * selected cell. To separate it from the double mouse click, the editing
 124:    * session starts after this time (in ms) after that single click, and only no
 125:    * other clicks were performed during that time.
 126:    */
 127:   static int WAIT_TILL_EDITING = 900;
 128: 
 129:   /** Collapse Icon for the tree. */
 130:   protected transient Icon collapsedIcon;
 131: 
 132:   /** Expanded Icon for the tree. */
 133:   protected transient Icon expandedIcon;
 134: 
 135:   /** Distance between left margin and where vertical dashes will be drawn. */
 136:   protected int leftChildIndent;
 137: 
 138:   /**
 139:    * Distance between leftChildIndent and where cell contents will be drawn.
 140:    */
 141:   protected int rightChildIndent;
 142: 
 143:   /**
 144:    * Total fistance that will be indented. The sum of leftChildIndent and
 145:    * rightChildIndent .
 146:    */
 147:   protected int totalChildIndent;
 148: 
 149:   /** Index of the row that was last selected. */
 150:   protected int lastSelectedRow;
 151: 
 152:   /** Component that we're going to be drawing onto. */
 153:   protected JTree tree;
 154: 
 155:   /** Renderer that is being used to do the actual cell drawing. */
 156:   protected transient TreeCellRenderer currentCellRenderer;
 157: 
 158:   /**
 159:    * Set to true if the renderer that is currently in the tree was created by
 160:    * this instance.
 161:    */
 162:   protected boolean createdRenderer;
 163: 
 164:   /** Editor for the tree. */
 165:   protected transient TreeCellEditor cellEditor;
 166: 
 167:   /**
 168:    * Set to true if editor that is currently in the tree was created by this
 169:    * instance.
 170:    */
 171:   protected boolean createdCellEditor;
 172: 
 173:   /**
 174:    * Set to false when editing and shouldSelectCall() returns true meaning the
 175:    * node should be selected before editing, used in completeEditing.
 176:    * GNU Classpath editing is implemented differently, so this value is not
 177:    * actually read anywhere. However it is always set correctly to maintain 
 178:    * interoperability with the derived classes that read this field.
 179:    */
 180:   protected boolean stopEditingInCompleteEditing;
 181: 
 182:   /** Used to paint the TreeCellRenderer. */
 183:   protected CellRendererPane rendererPane;
 184: 
 185:   /** Size needed to completely display all the nodes. */
 186:   protected Dimension preferredSize;
 187: 
 188:   /** Minimum size needed to completely display all the nodes. */
 189:   protected Dimension preferredMinSize;
 190: 
 191:   /** Is the preferredSize valid? */
 192:   protected boolean validCachedPreferredSize;
 193: 
 194:   /** Object responsible for handling sizing and expanded issues. */
 195:   protected AbstractLayoutCache treeState;
 196: 
 197:   /** Used for minimizing the drawing of vertical lines. */
 198:   protected Hashtable<TreePath, Boolean> drawingCache;
 199: 
 200:   /**
 201:    * True if doing optimizations for a largeModel. Subclasses that don't support
 202:    * this may wish to override createLayoutCache to not return a
 203:    * FixedHeightLayoutCache instance.
 204:    */
 205:   protected boolean largeModel;
 206: 
 207:   /** Responsible for telling the TreeState the size needed for a node. */
 208:   protected AbstractLayoutCache.NodeDimensions nodeDimensions;
 209: 
 210:   /** Used to determine what to display. */
 211:   protected TreeModel treeModel;
 212: 
 213:   /** Model maintaining the selection. */
 214:   protected TreeSelectionModel treeSelectionModel;
 215: 
 216:   /**
 217:    * How much the depth should be offset to properly calculate x locations. This
 218:    * is based on whether or not the root is visible, and if the root handles are
 219:    * visible.
 220:    */
 221:   protected int depthOffset;
 222: 
 223:   /**
 224:    * When editing, this will be the Component that is doing the actual editing.
 225:    */
 226:   protected Component editingComponent;
 227: 
 228:   /** Path that is being edited. */
 229:   protected TreePath editingPath;
 230: 
 231:   /**
 232:    * Row that is being edited. Should only be referenced if editingComponent is
 233:    * null.
 234:    */
 235:   protected int editingRow;
 236: 
 237:   /** Set to true if the editor has a different size than the renderer. */
 238:   protected boolean editorHasDifferentSize;
 239: 
 240:   /** Boolean to keep track of editing. */
 241:   boolean isEditing;
 242: 
 243:   /** The current path of the visible nodes in the tree. */
 244:   TreePath currentVisiblePath;
 245: 
 246:   /** The gap between the icon and text. */
 247:   int gap = 4;
 248: 
 249:   /** The max height of the nodes in the tree. */
 250:   int maxHeight;
 251:   
 252:   /** The hash color. */
 253:   Color hashColor;
 254: 
 255:   /** Listeners */
 256:   PropertyChangeListener propertyChangeListener;
 257: 
 258:   FocusListener focusListener;
 259: 
 260:   TreeSelectionListener treeSelectionListener;
 261: 
 262:   MouseListener mouseListener;
 263: 
 264:   KeyListener keyListener;
 265: 
 266:   PropertyChangeListener selectionModelPropertyChangeListener;
 267: 
 268:   ComponentListener componentListener;
 269: 
 270:   CellEditorListener cellEditorListener;
 271: 
 272:   TreeExpansionListener treeExpansionListener;
 273: 
 274:   TreeModelListener treeModelListener;
 275: 
 276:   /**
 277:    * The zero size icon, used for expand controls, if they are not visible.
 278:    */
 279:   static Icon nullIcon;
 280: 
 281:   /**
 282:    * The special value of the mouse event is sent indicating that this is not
 283:    * just the mouse click, but the mouse click on the selected node. Sending
 284:    * such event forces to start the cell editing session.
 285:    */
 286:   static final MouseEvent EDIT = new MouseEvent(new Label(), 7, 7, 7, 7, 7, 7,
 287:                                                 false);
 288: 
 289:   /**
 290:    * Creates a new BasicTreeUI object.
 291:    */
 292:   public BasicTreeUI()
 293:   {
 294:     validCachedPreferredSize = false;
 295:     drawingCache = new Hashtable();
 296:     nodeDimensions = createNodeDimensions();
 297:     configureLayoutCache();
 298: 
 299:     editingRow = - 1;
 300:     lastSelectedRow = - 1;
 301:   }
 302: 
 303:   /**
 304:    * Returns an instance of the UI delegate for the specified component.
 305:    * 
 306:    * @param c the <code>JComponent</code> for which we need a UI delegate for.
 307:    * @return the <code>ComponentUI</code> for c.
 308:    */
 309:   public static ComponentUI createUI(JComponent c)
 310:   {
 311:     return new BasicTreeUI();
 312:   }
 313: 
 314:   /**
 315:    * Returns the Hash color.
 316:    * 
 317:    * @return the <code>Color</code> of the Hash.
 318:    */
 319:   protected Color getHashColor()
 320:   {
 321:     return hashColor;
 322:   }
 323: 
 324:   /**
 325:    * Sets the Hash color.
 326:    * 
 327:    * @param color the <code>Color</code> to set the Hash to.
 328:    */
 329:   protected void setHashColor(Color color)
 330:   {
 331:     hashColor = color;
 332:   }
 333: 
 334:   /**
 335:    * Sets the left child's indent value.
 336:    * 
 337:    * @param newAmount is the new indent value for the left child.
 338:    */
 339:   public void setLeftChildIndent(int newAmount)
 340:   {
 341:     leftChildIndent = newAmount;
 342:   }
 343: 
 344:   /**
 345:    * Returns the indent value for the left child.
 346:    * 
 347:    * @return the indent value for the left child.
 348:    */
 349:   public int getLeftChildIndent()
 350:   {
 351:     return leftChildIndent;
 352:   }
 353: 
 354:   /**
 355:    * Sets the right child's indent value.
 356:    * 
 357:    * @param newAmount is the new indent value for the right child.
 358:    */
 359:   public void setRightChildIndent(int newAmount)
 360:   {
 361:     rightChildIndent = newAmount;
 362:   }
 363: 
 364:   /**
 365:    * Returns the indent value for the right child.
 366:    * 
 367:    * @return the indent value for the right child.
 368:    */
 369:   public int getRightChildIndent()
 370:   {
 371:     return rightChildIndent;
 372:   }
 373: 
 374:   /**
 375:    * Sets the expanded icon.
 376:    * 
 377:    * @param newG is the new expanded icon.
 378:    */
 379:   public void setExpandedIcon(Icon newG)
 380:   {
 381:     expandedIcon = newG;
 382:   }
 383: 
 384:   /**
 385:    * Returns the current expanded icon.
 386:    * 
 387:    * @return the current expanded icon.
 388:    */
 389:   public Icon getExpandedIcon()
 390:   {
 391:     return expandedIcon;
 392:   }
 393: 
 394:   /**
 395:    * Sets the collapsed icon.
 396:    * 
 397:    * @param newG is the new collapsed icon.
 398:    */
 399:   public void setCollapsedIcon(Icon newG)
 400:   {
 401:     collapsedIcon = newG;
 402:   }
 403: 
 404:   /**
 405:    * Returns the current collapsed icon.
 406:    * 
 407:    * @return the current collapsed icon.
 408:    */
 409:   public Icon getCollapsedIcon()
 410:   {
 411:     return collapsedIcon;
 412:   }
 413: 
 414:   /**
 415:    * Updates the componentListener, if necessary.
 416:    * 
 417:    * @param largeModel sets this.largeModel to it.
 418:    */
 419:   protected void setLargeModel(boolean largeModel)
 420:   {
 421:     if (largeModel != this.largeModel)
 422:       {
 423:         completeEditing();
 424:         tree.removeComponentListener(componentListener);
 425:         this.largeModel = largeModel;
 426:         tree.addComponentListener(componentListener);
 427:       }
 428:   }
 429: 
 430:   /**
 431:    * Returns true if largeModel is set
 432:    * 
 433:    * @return true if largeModel is set, otherwise false.
 434:    */
 435:   protected boolean isLargeModel()
 436:   {
 437:     return largeModel;
 438:   }
 439: 
 440:   /**
 441:    * Sets the row height.
 442:    * 
 443:    * @param rowHeight is the height to set this.rowHeight to.
 444:    */
 445:   protected void setRowHeight(int rowHeight)
 446:   {
 447:     completeEditing();
 448:     if (rowHeight == 0)
 449:       rowHeight = getMaxHeight(tree);
 450:     treeState.setRowHeight(rowHeight);
 451:   }
 452: 
 453:   /**
 454:    * Returns the current row height.
 455:    * 
 456:    * @return current row height.
 457:    */
 458:   protected int getRowHeight()
 459:   {
 460:     return tree.getRowHeight();
 461:   }
 462: 
 463:   /**
 464:    * Sets the TreeCellRenderer to <code>tcr</code>. This invokes
 465:    * <code>updateRenderer</code>.
 466:    * 
 467:    * @param tcr is the new TreeCellRenderer.
 468:    */
 469:   protected void setCellRenderer(TreeCellRenderer tcr)
 470:   {
 471:     // Finish editing before changing the renderer.
 472:     completeEditing();
 473: 
 474:     // The renderer is set in updateRenderer.
 475:     updateRenderer();
 476: 
 477:     // Refresh the layout if necessary.
 478:     if (treeState != null)
 479:       {
 480:     treeState.invalidateSizes();
 481:     updateSize();
 482:       }
 483:   }
 484: 
 485:   /**
 486:    * Return currentCellRenderer, which will either be the trees renderer, or
 487:    * defaultCellRenderer, which ever was not null.
 488:    * 
 489:    * @return the current Cell Renderer
 490:    */
 491:   protected TreeCellRenderer getCellRenderer()
 492:   {
 493:     if (currentCellRenderer != null)
 494:       return currentCellRenderer;
 495: 
 496:     return createDefaultCellRenderer();
 497:   }
 498: 
 499:   /**
 500:    * Sets the tree's model.
 501:    * 
 502:    * @param model to set the treeModel to.
 503:    */
 504:   protected void setModel(TreeModel model)
 505:   {
 506:     completeEditing();
 507: 
 508:     if (treeModel != null && treeModelListener != null)
 509:       treeModel.removeTreeModelListener(treeModelListener);
 510: 
 511:     treeModel = tree.getModel();
 512: 
 513:     if (treeModel != null && treeModelListener != null)
 514:       treeModel.addTreeModelListener(treeModelListener);
 515: 
 516:     if (treeState != null)
 517:       {
 518:         treeState.setModel(treeModel);
 519:         updateLayoutCacheExpandedNodes();
 520:         updateSize();
 521:       }
 522:   }
 523: 
 524:   /**
 525:    * Returns the tree's model
 526:    * 
 527:    * @return treeModel
 528:    */
 529:   protected TreeModel getModel()
 530:   {
 531:     return treeModel;
 532:   }
 533: 
 534:   /**
 535:    * Sets the root to being visible.
 536:    * 
 537:    * @param newValue sets the visibility of the root
 538:    */
 539:   protected void setRootVisible(boolean newValue)
 540:   {
 541:     completeEditing();
 542:     tree.setRootVisible(newValue);
 543:   }
 544: 
 545:   /**
 546:    * Returns true if the root is visible.
 547:    * 
 548:    * @return true if the root is visible.
 549:    */
 550:   protected boolean isRootVisible()
 551:   {
 552:     return tree.isRootVisible();
 553:   }
 554: 
 555:   /**
 556:    * Determines whether the node handles are to be displayed.
 557:    * 
 558:    * @param newValue sets whether or not node handles should be displayed.
 559:    */
 560:   protected void setShowsRootHandles(boolean newValue)
 561:   {
 562:     completeEditing();
 563:     updateDepthOffset();
 564:     if (treeState != null)
 565:       {
 566:         treeState.invalidateSizes();
 567:         updateSize();
 568:       }
 569:   }
 570: 
 571:   /**
 572:    * Returns true if the node handles are to be displayed.
 573:    * 
 574:    * @return true if the node handles are to be displayed.
 575:    */
 576:   protected boolean getShowsRootHandles()
 577:   {
 578:     return tree.getShowsRootHandles();
 579:   }
 580: 
 581:   /**
 582:    * Sets the cell editor.
 583:    * 
 584:    * @param editor to set the cellEditor to.
 585:    */
 586:   protected void setCellEditor(TreeCellEditor editor)
 587:   {
 588:     updateCellEditor();
 589:   }
 590: 
 591:   /**
 592:    * Returns the <code>TreeCellEditor</code> for this tree.
 593:    * 
 594:    * @return the cellEditor for this tree.
 595:    */
 596:   protected TreeCellEditor getCellEditor()
 597:   {
 598:     return cellEditor;
 599:   }
 600: 
 601:   /**
 602:    * Configures the receiver to allow, or not allow, editing.
 603:    * 
 604:    * @param newValue sets the receiver to allow editing if true.
 605:    */
 606:   protected void setEditable(boolean newValue)
 607:   {
 608:     updateCellEditor();
 609:   }
 610: 
 611:   /**
 612:    * Returns true if the receiver allows editing.
 613:    * 
 614:    * @return true if the receiver allows editing.
 615:    */
 616:   protected boolean isEditable()
 617:   {
 618:     return tree.isEditable();
 619:   }
 620: 
 621:   /**
 622:    * Resets the selection model. The appropriate listeners are installed on the
 623:    * model.
 624:    * 
 625:    * @param newLSM resets the selection model.
 626:    */
 627:   protected void setSelectionModel(TreeSelectionModel newLSM)
 628:   {
 629:     completeEditing();
 630:     if (newLSM != null)
 631:       {
 632:         treeSelectionModel = newLSM;
 633:         tree.setSelectionModel(treeSelectionModel);
 634:       }
 635:   }
 636: 
 637:   /**
 638:    * Returns the current selection model.
 639:    * 
 640:    * @return the current selection model.
 641:    */
 642:   protected TreeSelectionModel getSelectionModel()
 643:   {
 644:     return treeSelectionModel;
 645:   }
 646: 
 647:   /**
 648:    * Returns the Rectangle enclosing the label portion that the last item in
 649:    * path will be drawn to. Will return null if any component in path is
 650:    * currently valid.
 651:    * 
 652:    * @param tree is the current tree the path will be drawn to.
 653:    * @param path is the current path the tree to draw to.
 654:    * @return the Rectangle enclosing the label portion that the last item in the
 655:    *         path will be drawn to.
 656:    */
 657:   public Rectangle getPathBounds(JTree tree, TreePath path)
 658:   {
 659:     Rectangle bounds = null;
 660:     if (tree != null && treeState != null)
 661:       {
 662:         bounds = treeState.getBounds(path, null);
 663:         Insets i = tree.getInsets();
 664:         if (bounds != null && i != null)
 665:           {
 666:             bounds.x += i.left;
 667:             bounds.y += i.top;
 668:           }
 669:       }
 670:     return bounds;
 671:   }
 672: 
 673:   /**
 674:    * Returns the max height of all the nodes in the tree.
 675:    * 
 676:    * @param tree - the current tree
 677:    * @return the max height.
 678:    */
 679:   int getMaxHeight(JTree tree)
 680:   {
 681:     if (maxHeight != 0)
 682:       return maxHeight;
 683: 
 684:     Icon e = UIManager.getIcon("Tree.openIcon");
 685:     Icon c = UIManager.getIcon("Tree.closedIcon");
 686:     Icon l = UIManager.getIcon("Tree.leafIcon");
 687:     int rc = getRowCount(tree);
 688:     int iconHeight = 0;
 689: 
 690:     for (int row = 0; row < rc; row++)
 691:       {
 692:         if (isLeaf(row))
 693:           iconHeight = l.getIconHeight();
 694:         else if (tree.isExpanded(row))
 695:           iconHeight = e.getIconHeight();
 696:         else
 697:           iconHeight = c.getIconHeight();
 698: 
 699:         maxHeight = Math.max(maxHeight, iconHeight + gap);
 700:       }
 701:      
 702:     treeState.setRowHeight(maxHeight);
 703:     return maxHeight;
 704:   }
 705:   
 706:   /**
 707:    * Get the tree node icon.
 708:    */
 709:   Icon getNodeIcon(TreePath path)
 710:   {
 711:     Object node = path.getLastPathComponent();
 712:     if (treeModel.isLeaf(node))
 713:       return UIManager.getIcon("Tree.leafIcon");
 714:     else if (treeState.getExpandedState(path))
 715:       return UIManager.getIcon("Tree.openIcon");
 716:     else
 717:       return UIManager.getIcon("Tree.closedIcon");
 718:   }
 719: 
 720:   /**
 721:    * Returns the path for passed in row. If row is not visible null is returned.
 722:    * 
 723:    * @param tree is the current tree to return path for.
 724:    * @param row is the row number of the row to return.
 725:    * @return the path for passed in row. If row is not visible null is returned.
 726:    */
 727:   public TreePath getPathForRow(JTree tree, int row)
 728:   {
 729:     return treeState.getPathForRow(row);
 730:   }
 731: 
 732:   /**
 733:    * Returns the row that the last item identified in path is visible at. Will
 734:    * return -1 if any of the elments in the path are not currently visible.
 735:    * 
 736:    * @param tree is the current tree to return the row for.
 737:    * @param path is the path used to find the row.
 738:    * @return the row that the last item identified in path is visible at. Will
 739:    *         return -1 if any of the elments in the path are not currently
 740:    *         visible.
 741:    */
 742:   public int getRowForPath(JTree tree, TreePath path)
 743:   {
 744:     return treeState.getRowForPath(path);
 745:   }
 746: 
 747:   /**
 748:    * Returns the number of rows that are being displayed.
 749:    * 
 750:    * @param tree is the current tree to return the number of rows for.
 751:    * @return the number of rows being displayed.
 752:    */
 753:   public int getRowCount(JTree tree)
 754:   {
 755:     return treeState.getRowCount();
 756:   }
 757: 
 758:   /**
 759:    * Returns the path to the node that is closest to x,y. If there is nothing
 760:    * currently visible this will return null, otherwise it'll always return a
 761:    * valid path. If you need to test if the returned object is exactly at x,y
 762:    * you should get the bounds for the returned path and test x,y against that.
 763:    * 
 764:    * @param tree the tree to search for the closest path
 765:    * @param x is the x coordinate of the location to search
 766:    * @param y is the y coordinate of the location to search
 767:    * @return the tree path closes to x,y.
 768:    */
 769:   public TreePath getClosestPathForLocation(JTree tree, int x, int y)
 770:   {
 771:     return treeState.getPathClosestTo(x, y);
 772:   }
 773: 
 774:   /**
 775:    * Returns true if the tree is being edited. The item that is being edited can
 776:    * be returned by getEditingPath().
 777:    * 
 778:    * @param tree is the tree to check for editing.
 779:    * @return true if the tree is being edited.
 780:    */
 781:   public boolean isEditing(JTree tree)
 782:   {
 783:     return isEditing;
 784:   }
 785: 
 786:   /**
 787:    * Stops the current editing session. This has no effect if the tree is not
 788:    * being edited. Returns true if the editor allows the editing session to
 789:    * stop.
 790:    * 
 791:    * @param tree is the tree to stop the editing on
 792:    * @return true if the editor allows the editing session to stop.
 793:    */
 794:   public boolean stopEditing(JTree tree)
 795:   {
 796:     boolean ret = false;
 797:     if (editingComponent != null && cellEditor.stopCellEditing())
 798:       {
 799:         completeEditing(false, false, true);
 800:         ret = true;
 801:       }
 802:     return ret;
 803:   }
 804: 
 805:   /**
 806:    * Cancels the current editing session.
 807:    * 
 808:    * @param tree is the tree to cancel the editing session on.
 809:    */
 810:   public void cancelEditing(JTree tree)
 811:   {
 812:     // There is no need to send the cancel message to the editor,
 813:     // as the cancellation event itself arrives from it. This would
 814:     // only be necessary when cancelling the editing programatically.
 815:     if (editingComponent != null)
 816:       completeEditing(false, true, false);
 817:   }
 818: 
 819:   /**
 820:    * Selects the last item in path and tries to edit it. Editing will fail if
 821:    * the CellEditor won't allow it for the selected item.
 822:    * 
 823:    * @param tree is the tree to edit on.
 824:    * @param path is the path in tree to edit on.
 825:    */
 826:   public void startEditingAtPath(JTree tree, TreePath path)
 827:   {
 828:     tree.scrollPathToVisible(path);
 829:     if (path != null && tree.isVisible(path))
 830:       startEditing(path, null);
 831:   }
 832: 
 833:   /**
 834:    * Returns the path to the element that is being editted.
 835:    * 
 836:    * @param tree is the tree to get the editing path from.
 837:    * @return the path that is being edited.
 838:    */
 839:   public TreePath getEditingPath(JTree tree)
 840:   {
 841:     return editingPath;
 842:   }
 843: 
 844:   /**
 845:    * Invoked after the tree instance variable has been set, but before any
 846:    * default/listeners have been installed.
 847:    */
 848:   protected void prepareForUIInstall()
 849:   {
 850:     lastSelectedRow = -1;
 851:     preferredSize = new Dimension();
 852:     largeModel = tree.isLargeModel();
 853:     preferredSize = new Dimension();
 854:     stopEditingInCompleteEditing = true;
 855:     setModel(tree.getModel());
 856:   }
 857: 
 858:   /**
 859:    * Invoked from installUI after all the defaults/listeners have been
 860:    * installed.
 861:    */
 862:   protected void completeUIInstall()
 863:   {
 864:     setShowsRootHandles(tree.getShowsRootHandles());
 865:     updateRenderer();
 866:     updateDepthOffset();
 867:     setSelectionModel(tree.getSelectionModel());
 868:     configureLayoutCache();
 869:     treeState.setRootVisible(tree.isRootVisible()); 
 870:     treeSelectionModel.setRowMapper(treeState);
 871:     updateSize();
 872:   }
 873: 
 874:   /**
 875:    * Invoked from uninstallUI after all the defaults/listeners have been
 876:    * uninstalled.
 877:    */
 878:   protected void completeUIUninstall()
 879:   {
 880:     tree = null;
 881:   }
 882: 
 883:   /**
 884:    * Installs the subcomponents of the tree, which is the renderer pane.
 885:    */
 886:   protected void installComponents()
 887:   {
 888:     currentCellRenderer = createDefaultCellRenderer();
 889:     rendererPane = createCellRendererPane();
 890:     createdRenderer = true;
 891:     setCellRenderer(currentCellRenderer);
 892:   }
 893: 
 894:   /**
 895:    * Creates an instance of NodeDimensions that is able to determine the size of
 896:    * a given node in the tree. The node dimensions must be created before
 897:    * configuring the layout cache.
 898:    * 
 899:    * @return the NodeDimensions of a given node in the tree
 900:    */
 901:   protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
 902:   {
 903:     return new NodeDimensionsHandler();
 904:   }
 905: 
 906:   /**
 907:    * Creates a listener that is reponsible for the updates the UI based on how
 908:    * the tree changes.
 909:    * 
 910:    * @return the PropertyChangeListener that is reposnsible for the updates
 911:    */
 912:   protected PropertyChangeListener createPropertyChangeListener()
 913:   {
 914:     return new PropertyChangeHandler();
 915:   }
 916: 
 917:   /**
 918:    * Creates the listener responsible for updating the selection based on mouse
 919:    * events.
 920:    * 
 921:    * @return the MouseListener responsible for updating.
 922:    */
 923:   protected MouseListener createMouseListener()
 924:   {
 925:     return new MouseHandler();
 926:   }
 927: 
 928:   /**
 929:    * Creates the listener that is responsible for updating the display when
 930:    * focus is lost/grained.
 931:    * 
 932:    * @return the FocusListener responsible for updating.
 933:    */
 934:   protected FocusListener createFocusListener()
 935:   {
 936:     return new FocusHandler();
 937:   }
 938: 
 939:   /**
 940:    * Creates the listener reponsible for getting key events from the tree.
 941:    * 
 942:    * @return the KeyListener responsible for getting key events.
 943:    */
 944:   protected KeyListener createKeyListener()
 945:   {
 946:     return new KeyHandler();
 947:   }
 948: 
 949:   /**
 950:    * Creates the listener responsible for getting property change events from
 951:    * the selection model.
 952:    * 
 953:    * @returns the PropertyChangeListener reponsible for getting property change
 954:    *          events from the selection model.
 955:    */
 956:   protected PropertyChangeListener createSelectionModelPropertyChangeListener()
 957:   {
 958:     return new SelectionModelPropertyChangeHandler();
 959:   }
 960: 
 961:   /**
 962:    * Creates the listener that updates the display based on selection change
 963:    * methods.
 964:    * 
 965:    * @return the TreeSelectionListener responsible for updating.
 966:    */
 967:   protected TreeSelectionListener createTreeSelectionListener()
 968:   {
 969:     return new TreeSelectionHandler();
 970:   }
 971: 
 972:   /**
 973:    * Creates a listener to handle events from the current editor