Source for javax.swing.plaf.basic.BasicTreeUI

   1: /* BasicTreeUI.java --
   2:  Copyright (C) 2002, 2004, 2005 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 java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Dimension;
  44: import java.awt.Font;
  45: import java.awt.FontMetrics;
  46: import java.awt.Graphics;
  47: import java.awt.Point;
  48: import java.awt.Rectangle;
  49: import java.awt.event.ActionEvent;
  50: import java.awt.event.ActionListener;
  51: import java.awt.event.ComponentAdapter;
  52: import java.awt.event.ComponentEvent;
  53: import java.awt.event.ComponentListener;
  54: import java.awt.event.FocusEvent;
  55: import java.awt.event.FocusListener;
  56: import java.awt.event.KeyAdapter;
  57: import java.awt.event.KeyEvent;
  58: import java.awt.event.KeyListener;
  59: import java.awt.event.MouseAdapter;
  60: import java.awt.event.MouseEvent;
  61: import java.awt.event.MouseListener;
  62: import java.awt.event.MouseMotionListener;
  63: import java.beans.PropertyChangeEvent;
  64: import java.beans.PropertyChangeListener;
  65: import java.util.Hashtable;
  66: 
  67: import javax.swing.AbstractAction;
  68: import javax.swing.Action;
  69: import javax.swing.ActionMap;
  70: import javax.swing.CellRendererPane;
  71: import javax.swing.Icon;
  72: import javax.swing.InputMap;
  73: import javax.swing.JComponent;
  74: import javax.swing.JScrollBar;
  75: import javax.swing.JScrollPane;
  76: import javax.swing.JTextField;
  77: import javax.swing.JTree;
  78: import javax.swing.KeyStroke;
  79: import javax.swing.SwingUtilities;
  80: import javax.swing.Timer;
  81: import javax.swing.UIDefaults;
  82: import javax.swing.UIManager;
  83: import javax.swing.event.CellEditorListener;
  84: import javax.swing.event.ChangeEvent;
  85: import javax.swing.event.MouseInputListener;
  86: import javax.swing.event.TreeExpansionEvent;
  87: import javax.swing.event.TreeExpansionListener;
  88: import javax.swing.event.TreeModelEvent;
  89: import javax.swing.event.TreeModelListener;
  90: import javax.swing.event.TreeSelectionEvent;
  91: import javax.swing.event.TreeSelectionListener;
  92: import javax.swing.plaf.ComponentUI;
  93: import javax.swing.plaf.InputMapUIResource;
  94: import javax.swing.plaf.TreeUI;
  95: import javax.swing.text.Caret;
  96: import javax.swing.tree.AbstractLayoutCache;
  97: import javax.swing.tree.DefaultTreeCellEditor;
  98: import javax.swing.tree.DefaultTreeCellRenderer;
  99: import javax.swing.tree.ExpandVetoException;
 100: import javax.swing.tree.FixedHeightLayoutCache;
 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: 
 108: /**
 109:  * A delegate providing the user interface for <code>JTree</code> according to
 110:  * the Basic look and feel.
 111:  * 
 112:  * @see javax.swing.JTree
 113:  * @author Sascha Brawer (brawer@dandelis.ch)
 114:  * @author Lillian Angel (langel@redhat.com)
 115:  */
 116: public class BasicTreeUI
 117:   extends TreeUI
 118: {
 119:   /** Collapse Icon for the tree. */
 120:   protected transient Icon collapsedIcon;
 121: 
 122:   /** Expanded Icon for the tree. */
 123:   protected transient Icon expandedIcon;
 124: 
 125:   /** Distance between left margin and where vertical dashes will be drawn. */
 126:   protected int leftChildIndent;
 127: 
 128:   /**
 129:    * Distance between leftChildIndent and where cell contents will be drawn.
 130:    */
 131:   protected int rightChildIndent;
 132: 
 133:   /**
 134:    * Total fistance that will be indented. The sum of leftChildIndent and
 135:    * rightChildIndent .
 136:    */
 137:   protected int totalChildIndent;
 138: 
 139:   /** Minimum preferred size. */
 140:   protected Dimension preferredMinsize;
 141: 
 142:   /** Index of the row that was last selected. */
 143:   protected int lastSelectedRow;
 144: 
 145:   /** Component that we're going to be drawing onto. */
 146:   protected JTree tree;
 147: 
 148:   /** Renderer that is being used to do the actual cell drawing. */
 149:   protected transient TreeCellRenderer currentCellRenderer;
 150: 
 151:   /**
 152:    * Set to true if the renderer that is currently in the tree was created by
 153:    * this instance.
 154:    */
 155:   protected boolean createdRenderer;
 156: 
 157:   /** Editor for the tree. */
 158:   protected transient TreeCellEditor cellEditor;
 159: 
 160:   /**
 161:    * Set to true if editor that is currently in the tree was created by this
 162:    * instance.
 163:    */
 164:   protected boolean createdCellEditor;
 165: 
 166:   /**
 167:    * Set to false when editing and shouldSelectCall() returns true meaning the
 168:    * node should be selected before editing, used in completeEditing.
 169:    */
 170:   protected boolean stopEditingInCompleteEditing;
 171: 
 172:   /** Used to paint the TreeCellRenderer. */
 173:   protected CellRendererPane rendererPane;
 174: 
 175:   /** Size needed to completely display all the nodes. */
 176:   protected Dimension preferredSize;
 177: 
 178:   /** Is the preferredSize valid? */
 179:   protected boolean validCachedPreferredSize;
 180: 
 181:   /** Object responsible for handling sizing and expanded issues. */
 182:   protected AbstractLayoutCache treeState;
 183: 
 184:   /** Used for minimizing the drawing of vertical lines. */
 185:   protected Hashtable drawingCache;
 186: 
 187:   /**
 188:    * True if doing optimizations for a largeModel. Subclasses that don't support
 189:    * this may wish to override createLayoutCache to not return a
 190:    * FixedHeightLayoutCache instance.
 191:    */
 192:   protected boolean largeModel;
 193: 
 194:   /** Responsible for telling the TreeState the size needed for a node. */
 195:   protected AbstractLayoutCache.NodeDimensions nodeDimensions;
 196: 
 197:   /** Used to determine what to display. */
 198:   protected TreeModel treeModel;
 199: 
 200:   /** Model maintaining the selection. */
 201:   protected TreeSelectionModel treeSelectionModel;
 202: 
 203:   /**
 204:    * How much the depth should be offset to properly calculate x locations. This
 205:    * is based on whether or not the root is visible, and if the root handles are
 206:    * visible.
 207:    */
 208:   protected int depthOffset;
 209: 
 210:   /**
 211:    * When editing, this will be the Component that is doing the actual editing.
 212:    */
 213:   protected Component editingComponent;
 214: 
 215:   /** Path that is being edited. */
 216:   protected TreePath editingPath;
 217: 
 218:   /**
 219:    * Row that is being edited. Should only be referenced if editingComponent is
 220:    * null.
 221:    */
 222:   protected int editingRow;
 223: 
 224:   /** Set to true if the editor has a different size than the renderer. */
 225:   protected boolean editorHasDifferentSize;
 226: 
 227:   /** The action listener for the editor's Timer. */
 228:   private Timer editorTimer = new EditorUpdateTimer();
 229: 
 230:   /** The new value of the node after editing. */
 231:   private Object newVal;
 232: 
 233:   /** The action bound to KeyStrokes. */
 234:   private TreeAction action;
 235:   
 236:   /** Boolean to keep track of editing. */
 237:   private boolean isEditing;
 238: 
 239:   /** Listeners */
 240:   private PropertyChangeListener propertyChangeListener;
 241: 
 242:   private FocusListener focusListener;
 243: 
 244:   private TreeSelectionListener treeSelectionListener;
 245: 
 246:   private MouseInputListener mouseInputListener;
 247: 
 248:   private KeyListener keyListener;
 249: 
 250:   private PropertyChangeListener selectionModelPropertyChangeListener;
 251: 
 252:   private ComponentListener componentListener;
 253: 
 254:   private CellEditorListener cellEditorListener;
 255: 
 256:   private TreeExpansionListener treeExpansionListener;
 257: 
 258:   private TreeModelListener treeModelListener;
 259: 
 260:   /**
 261:    * Creates a new BasicTreeUI object.
 262:    */
 263:   public BasicTreeUI()
 264:   {
 265:     drawingCache = new Hashtable();
 266:     nodeDimensions = createNodeDimensions();
 267:     configureLayoutCache();
 268: 
 269:     propertyChangeListener = createPropertyChangeListener();
 270:     focusListener = createFocusListener();
 271:     treeSelectionListener = createTreeSelectionListener();
 272:     mouseInputListener = new MouseInputHandler(null, null, null);
 273:     keyListener = createKeyListener();
 274:     selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener();
 275:     componentListener = createComponentListener();
 276:     cellEditorListener = createCellEditorListener();
 277:     treeExpansionListener = createTreeExpansionListener();
 278:     treeModelListener = createTreeModelListener();
 279: 
 280:     editingRow = -1;
 281:     lastSelectedRow = -1;
 282:   }
 283: 
 284:   /**
 285:    * Returns an instance of the UI delegate for the specified component.
 286:    * 
 287:    * @param c
 288:    *          the <code>JComponent</code> for which we need a UI delegate for.
 289:    * @return the <code>ComponentUI</code> for c.
 290:    */
 291:   public static ComponentUI createUI(JComponent c)
 292:   {
 293:     return new BasicTreeUI();
 294:   }
 295: 
 296:   /**
 297:    * Returns the Hash color.
 298:    * 
 299:    * @return the <code>Color</code> of the Hash.
 300:    */
 301:   protected Color getHashColor()
 302:   {
 303:     return UIManager.getLookAndFeelDefaults().getColor("Tree.hash");
 304:   }
 305: 
 306:   /**
 307:    * Sets the Hash color.
 308:    * 
 309:    * @param color
 310:    *          the <code>Color</code> to set the Hash to.
 311:    */
 312:   protected void setHashColor(Color color)
 313:   {
 314:     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
 315:     defaults.put("Tree.hash", color);
 316:   }
 317: 
 318:   /**
 319:    * Sets the left child's indent value.
 320:    * 
 321:    * @param newAmount
 322:    *          is the new indent value for the left child.
 323:    */
 324:   public void setLeftChildIndent(int newAmount)
 325:   {
 326:     leftChildIndent = newAmount;
 327:   }
 328: 
 329:   /**
 330:    * Returns the indent value for the left child.
 331:    * 
 332:    * @return the indent value for the left child.
 333:    */
 334:   public int getLeftChildIndent(int newAmount)
 335:   {
 336:     return leftChildIndent;
 337:   }
 338: 
 339:   /**
 340:    * Sets the right child's indent value.
 341:    * 
 342:    * @param newAmount
 343:    *          is the new indent value for the right child.
 344:    */
 345:   public void setRightChildIndent(int newAmount)
 346:   {
 347:     rightChildIndent = newAmount;
 348:   }
 349: 
 350:   /**
 351:    * Returns the indent value for the right child.
 352:    * 
 353:    * @return the indent value for the right child.
 354:    */
 355:   public int getRightChildIndent()
 356:   {
 357:     return rightChildIndent;
 358:   }
 359: 
 360:   /**
 361:    * Sets the expanded icon.
 362:    * 
 363:    * @param newG
 364:    *          is the new expanded icon.
 365:    */
 366:   public void setExpandedIcon(Icon newG)
 367:   {
 368:     expandedIcon = newG;
 369:   }
 370: 
 371:   /**
 372:    * Returns the current expanded icon.
 373:    * 
 374:    * @return the current expanded icon.
 375:    */
 376:   public Icon getExpandedIcon()
 377:   {
 378:     return expandedIcon;
 379:   }
 380: 
 381:   /**
 382:    * Sets the collapsed icon.
 383:    * 
 384:    * @param newG
 385:    *          is the new collapsed icon.
 386:    */
 387:   public void setCollapsedIcon(Icon newG)
 388:   {
 389:     collapsedIcon = newG;
 390:   }
 391: 
 392:   /**
 393:    * Returns the current collapsed icon.
 394:    * 
 395:    * @return the current collapsed icon.
 396:    */
 397:   public Icon getCollapsedIcon()
 398:   {
 399:     return collapsedIcon;
 400:   }
 401: 
 402:   /**
 403:    * Updates the componentListener, if necessary.
 404:    * 
 405:    * @param largeModel
 406:    *          sets this.largeModel to it.
 407:    */
 408:   protected void setLargeModel(boolean largeModel)
 409:   {
 410:     if (largeModel != this.largeModel)
 411:       {
 412:         tree.removeComponentListener(componentListener);
 413:         this.largeModel = largeModel;
 414:         tree.addComponentListener(componentListener);
 415:       }
 416:   }
 417: 
 418:   /**
 419:    * Returns true if largeModel is set
 420:    * 
 421:    * @return true if largeModel is set, otherwise false.
 422:    */
 423:   protected boolean isLargeModel()
 424:   {
 425:     return largeModel;
 426:   }
 427: 
 428:   /**
 429:    * Sets the row height.
 430:    * 
 431:    * @param rowHeight
 432:    *          is the height to set this.rowHeight to.
 433:    */
 434:   protected void setRowHeight(int rowHeight)
 435:   {
 436:     treeState.setRowHeight(rowHeight);
 437:   }
 438: 
 439:   /**
 440:    * Returns the current row height.
 441:    * 
 442:    * @return current row height.
 443:    */
 444:   protected int getRowHeight()
 445:   {
 446:     return treeState.getRowHeight();
 447:   }
 448: 
 449:   /**
 450:    * Sets the TreeCellRenderer to <code>tcr</code>. This invokes
 451:    * <code>updateRenderer</code>.
 452:    * 
 453:    * @param tcr
 454:    *          is the new TreeCellRenderer.
 455:    */
 456:   protected void setCellRenderer(TreeCellRenderer tcr)
 457:   {
 458:     currentCellRenderer = tcr;
 459:     tree.setCellRenderer(tcr);
 460:     updateRenderer();
 461:   }
 462: 
 463:   /**
 464:    * Return currentCellRenderer, which will either be the trees renderer, or
 465:    * defaultCellRenderer, which ever was not null.
 466:    * 
 467:    * @return the current Cell Renderer
 468:    */
 469:   protected TreeCellRenderer getCellRenderer()
 470:   {
 471:     if (currentCellRenderer != null)
 472:       return currentCellRenderer;
 473: 
 474:     return createDefaultCellRenderer();
 475:   }
 476: 
 477:   /**
 478:    * Sets the tree's model.
 479:    * 
 480:    * @param model
 481:    *          to set the treeModel to.
 482:    */
 483:   protected void setModel(TreeModel model)
 484:   {
 485:     tree.setModel(model);
 486:     treeModel = tree.getModel();
 487:   }
 488: 
 489:   /**
 490:    * Returns the tree's model
 491:    * 
 492:    * @return treeModel
 493:    */
 494:   protected TreeModel getModel()
 495:   {
 496:     return treeModel;
 497:   }
 498: 
 499:   /**
 500:    * Sets the root to being visible.
 501:    * 
 502:    * @param newValue
 503:    *          sets the visibility of the root
 504:    */
 505:   protected void setRootVisible(boolean newValue)
 506:   {
 507:     tree.setRootVisible(newValue);
 508:   }
 509: 
 510:   /**
 511:    * Returns true if the root is visible.
 512:    * 
 513:    * @return true if the root is visible.
 514:    */
 515:   protected boolean isRootVisible()
 516:   {
 517:     return tree.isRootVisible();
 518:   }
 519: 
 520:   /**
 521:    * Determines whether the node handles are to be displayed.
 522:    * 
 523:    * @param newValue
 524:    *          sets whether or not node handles should be displayed.
 525:    */
 526:   protected void setShowsRootHandles(boolean newValue)
 527:   {
 528:     tree.setShowsRootHandles(newValue);
 529:   }
 530: 
 531:   /**
 532:    * Returns true if the node handles are to be displayed.
 533:    * 
 534:    * @return true if the node handles are to be displayed.
 535:    */
 536:   protected boolean getShowsRootHandles()
 537:   {
 538:     return tree.getShowsRootHandles();
 539:   }
 540: 
 541:   /**
 542:    * Sets the cell editor.
 543:    * 
 544:    * @param editor
 545:    *          to set the cellEditor to.
 546:    */
 547:   protected void setCellEditor(TreeCellEditor editor)
 548:   {
 549:     cellEditor = editor;
 550:     createdCellEditor = true;
 551:   }
 552: 
 553:   /**
 554:    * Returns the <code>TreeCellEditor</code> for this tree.
 555:    * 
 556:    * @return the cellEditor for this tree.
 557:    */
 558:   protected TreeCellEditor getCellEditor()
 559:   {
 560:     return cellEditor;
 561:   }
 562: 
 563:   /**
 564:    * Configures the receiver to allow, or not allow, editing.
 565:    * 
 566:    * @param newValue
 567:    *          sets the receiver to allow editing if true.
 568:    */
 569:   protected void setEditable(boolean newValue)
 570:   {
 571:     tree.setEditable(newValue);
 572:   }
 573: 
 574:   /**
 575:    * Returns true if the receiver allows editing.
 576:    * 
 577:    * @return true if the receiver allows editing.
 578:    */
 579:   protected boolean isEditable()
 580:   {
 581:     return tree.isEditable();
 582:   }
 583: 
 584:   /**
 585:    * Resets the selection model. The appropriate listeners are installed on the
 586:    * model.
 587:    * 
 588:    * @param newLSM
 589:    *          resets the selection model.
 590:    */
 591:   protected void setSelectionModel(TreeSelectionModel newLSM)
 592:   {
 593:     if (newLSM != null)
 594:       {
 595:         treeSelectionModel = newLSM;
 596:         tree.setSelectionModel(treeSelectionModel);
 597:       }
 598:   }
 599: 
 600:   /**
 601:    * Returns the current selection model.
 602:    * 
 603:    * @return the current selection model.
 604:    */
 605:   protected TreeSelectionModel getSelectionModel()
 606:   {
 607:     return treeSelectionModel;
 608:   }
 609: 
 610:   /**
 611:    * Returns the Rectangle enclosing the label portion that the last item in
 612:    * path will be drawn to. Will return null if any component in path is
 613:    * currently valid.
 614:    * 
 615:    * @param tree
 616:    *          is the current tree the path will be drawn to.
 617:    * @param path
 618:    *          is the current path the tree to draw to.
 619:    * @return the Rectangle enclosing the label portion that the last item in the
 620:    *         path will be drawn to.
 621:    */
 622:   public Rectangle getPathBounds(JTree tree, TreePath path)
 623:   {
 624:     if (path != null)
 625:       {
 626:         Object cell = path.getLastPathComponent();
 627: 
 628:         TreeModel mod = tree.getModel();
 629:         if (mod != null)
 630:           {
 631:             Object root = mod.getRoot();
 632:             if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root)))
 633:               root = getNextNode(root);
 634: 
 635:             Point loc = getCellLocation(0, 0, tree, mod, cell, root);
 636:             return getCellBounds(loc.x, loc.y, cell);
 637:           }
 638:       }
 639:     return null;
 640:   }
 641: 
 642:   /**
 643:    * Returns the path for passed in row. If row is not visible null is returned.
 644:    * 
 645:    * @param tree
 646:    *          is the current tree to return path for.
 647:    * @param row
 648:    *          is the row number of the row to return.
 649:    * @return the path for passed in row. If row is not visible null is returned.
 650:    */
 651:   public TreePath getPathForRow(JTree tree, int row)
 652:   {
 653:     TreeModel mod = tree.getModel();
 654:     if (mod != null)
 655:       {
 656:         Object node = mod.getRoot();
 657:         if (!tree.isRootVisible()
 658:             && tree.isExpanded(new TreePath(getPathToRoot(node, 0))))
 659:           node = getNextNode(node);
 660: 
 661:         for (int i = 0; i < row; i++)
 662:           node = getNextVisibleNode(node);
 663: 
 664:         if (node == null)
 665:           return null;
 666: 
 667:         return new TreePath(getPathToRoot(node, 0));
 668:       }
 669:     return null;
 670:   }
 671: 
 672:   /**
 673:    * Returns the row that the last item identified in path is visible at. Will
 674:    * return -1 if any of the elments in the path are not currently visible.
 675:    * 
 676:    * @param tree
 677:    *          is the current tree to return the row for.
 678:    * @param path
 679:    *          is the path used to find the row.
 680:    * @return the row that the last item identified in path is visible at. Will
 681:    *         return -1 if any of the elments in the path are not currently
 682:    *         visible.
 683:    */
 684:   public int getRowForPath(JTree tree, TreePath path)
 685:   {
 686:     int row = path.getPathCount();
 687:     if (tree.isVisible(path))
 688:       return row;
 689: 
 690:     path = path.getParentPath();
 691:     while (row > 0 && !tree.isVisible(path))
 692:       {
 693:         path = path.getParentPath();
 694:         row--;
 695:       }
 696:     return row;
 697:   }
 698: 
 699:   /**
 700:    * Returns the number of rows that are being displayed.
 701:    * 
 702:    * @param tree
 703:    *          is the current tree to return the number of rows for.
 704:    * @return the number of rows being displayed.
 705:    */
 706:   public int getRowCount(JTree tree)
 707:   {
 708:     TreeModel mod = tree.getModel();
 709:     int count = 0;
 710:     if (mod != null)
 711:       {
 712:         Object node = mod.getRoot();
 713:         if (!tree.isRootVisible()
 714:             && tree.isExpanded(new TreePath((getPathToRoot(node, 0)))))
 715:           node = getNextNode(node);
 716: 
 717:         while (node != null)
 718:           {
 719:             count++;
 720:             node = getNextVisibleNode(node);
 721:           }
 722:       }
 723:     return count;
 724:   }
 725: 
 726:   /**
 727:    * Returns the path to the node that is closest to x,y. If there is nothing
 728:    * currently visible this will return null, otherwise it'll always return a
 729:    * valid path. If you need to test if the returned object is exactly at x,y
 730:    * you should get the bounds for the returned path and test x,y against that.
 731:    * 
 732:    * @param tree
 733:    *          the tree to search for the closest path
 734:    * @param x
 735:    *          is the x coordinate of the location to search
 736:    * @param y
 737:    *          is the y coordinate of the location to search
 738:    * @return the tree path closes to x,y.
 739:    */
 740:   public TreePath getClosestPathForLocation(JTree tree, int x, int y)
 741:   {
 742:     // FIXME: what if root is hidden? should not depend on (0,0)
 743:     // should start counting rows from where root is.
 744: 
 745:     int row = Math.round(y / getRowHeight());
 746:     TreePath path = getPathForRow(tree, row);
 747: 
 748:     // no row is visible at this node
 749:     while (row > 0 && path == null)
 750:       {
 751:         --row;
 752:         path = getPathForRow(tree, row);
 753:       }
 754: 
 755:     return path;
 756:   }
 757: 
 758:   /**
 759:    * Returns true if the tree is being edited. The item that is being edited can
 760:    * be returned by getEditingPath().
 761:    * 
 762:    * @param tree
 763:    *          is the tree to check for editing.
 764:    * @return true if the tree is being edited.
 765:    */
 766:   public boolean isEditing(JTree tree)
 767:   {
 768:     return isEditing;
 769:   }
 770: 
 771:   /**
 772:    * Stops the current editing session. This has no effect if the tree is not
 773:    * being edited. Returns true if the editor allows the editing session to
 774:    * stop.
 775:    * 
 776:    * @param tree
 777:    *          is the tree to stop the editing on
 778:    * @return true if the editor allows the editing session to stop.
 779:    */
 780:   public boolean stopEditing(JTree tree)
 781:   {
 782:     if (isEditing(tree))
 783:       completeEditing(true, false, false);
 784:     return !isEditing(tree);
 785:   }
 786: 
 787:   /**
 788:    * Cancels the current editing session.
 789:    * 
 790:    * @param tree
 791:    *          is the tree to cancel the editing session on.
 792:    */
 793:   public void cancelEditing(JTree tree)
 794:   {
 795:     if (isEditing(tree))
 796:       completeEditing(false, true, false);
 797:   }
 798: 
 799:   /**
 800:    * Selects the last item in path and tries to edit it. Editing will fail if
 801:    * the CellEditor won't allow it for the selected item.
 802:    * 
 803:    * @param tree
 804:    *          is the tree to edit on.
 805:    * @param path
 806:    *          is the path in tree to edit on.
 807:    */
 808:   public void startEditingAtPath(JTree tree, TreePath path)
 809:   {
 810:     startEditing(path, null);
 811:   }
 812: 
 813:   /**
 814:    * Returns the path to the element that is being editted.
 815:    * 
 816:    * @param tree
 817:    *          is the tree to get the editing path from.
 818:    * @return the path that is being edited.
 819:    */
 820:   public TreePath getEditingPath(JTree tree)
 821:   {
 822:     return editingPath;
 823:   }
 824: 
 825:   /**
 826:    * Invoked after the tree instance variable has been set, but before any
 827:    * default/listeners have been installed.
 828:    */
 829:   protected void prepareForUIInstall()
 830:   {
 831:     // FIXME: not implemented
 832:   }
 833: 
 834:   /**
 835:    * Invoked from installUI after all the defaults/listeners have been
 836:    * installed.
 837:    */
 838:   protected void completeUIInstall()
 839:   {
 840:     // FIXME: not implemented
 841:   }
 842: 
 843:   /**
 844:    * Invoked from uninstallUI after all the defaults/listeners have been
 845:    * uninstalled.
 846:    */
 847:   protected void completeUIUninstall()
 848:   {
 849:     // FIXME: not implemented
 850:   }
 851: 
 852:   /**
 853:    * Installs the subcomponents of the tree, which is the renderer pane.
 854:    */
 855:   protected void installComponents()
 856:   {
 857:     // FIXME: not implemented
 858:   }
 859: 
 860:   /**
 861:    * Creates an instance of NodeDimensions that is able to determine the size of
 862:    * a given node in the tree.
 863:    * 
 864:    * @return the NodeDimensions of a given node in the tree
 865:    */
 866:   protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
 867:   {
 868:     // FIXME: not implemented
 869:     return null;
 870:   }
 871: 
 872:   /**
 873:    * Creates a listener that is reponsible for the updates the UI based on how
 874:    * the tree changes.
 875:    * 
 876:    * @return the PropertyChangeListener that is reposnsible for the updates
 877:    */
 878:   protected PropertyChangeListener createPropertyChangeListener()
 879:   {
 880:     return new PropertyChangeHandler();
 881:   }
 882: 
 883:   /**
 884:    * Creates the listener responsible for updating the selection based on mouse
 885:    * events.
 886:    * 
 887:    * @return the MouseListener responsible for updating.
 888:    */
 889:   protected MouseListener createMouseListener()
 890:   {
 891:     return new MouseHandler();
 892:   }
 893: 
 894:   /**
 895:    * Creates the listener that is responsible for updating the display when
 896:    * focus is lost/grained.
 897:    * 
 898:    * @return the FocusListener responsible for updating.
 899:    */
 900:   protected FocusListener createFocusListener()
 901:   {
 902:     return new FocusHandler();
 903:   }
 904: 
 905:   /**
 906:    * Creates the listener reponsible for getting key events from the tree.
 907:    * 
 908:    * @return the KeyListener responsible for getting key events.
 909:    */
 910:   protected KeyListener createKeyListener()
 911:   {
 912:     return new KeyHandler();
 913:   }
 914: 
 915:   /**
 916:    * Creates the listener responsible for getting property change events from
 917:    * the selection model.
 918:    * 
 919:    * @returns the PropertyChangeListener reponsible for getting property change
 920:    *          events from the selection model.
 921:    */
 922:   protected PropertyChangeListener createSelectionModelPropertyChangeListener()
 923:   {
 924:     return new SelectionModelPropertyChangeHandler();
 925:   }
 926: 
 927:   /**
 928:    * Creates the listener that updates the display based on selection change
 929:    * methods.
 930:    * 
 931:    * @return the TreeSelectionListener responsible for updating.
 932:    */
 933:   protected TreeSelectionListener createTreeSelectionListener()
 934:   {
 935:     return new TreeSelectionHandler();
 936:   }
 937: 
 938:   /**
 939:    * Creates a listener to handle events from the current editor
 940:    * 
 941:    * @return the CellEditorListener that handles events from the current editor
 942:    */
 943:   protected CellEditorListener createCellEditorListener()
 944:   {
 945:     return new CellEditorHandler();
 946:   }
 947: 
 948:   /**
 949:    * Creates and returns a new ComponentHandler. This is used for the large
 950:    * model to mark the validCachedPreferredSize as invalid when the component
 951:    * moves.
 952:    * 
 953:    * @return a new ComponentHandler.
 954:    */
 955:   protected ComponentListener createComponentListener()
 956:   {
 957:     return new ComponentHandler();
 958:   }
 959: 
 960:   /**
 961:    * Creates and returns the object responsible for updating the treestate when
 962:    * a nodes expanded state changes.
 963:    * 
 964:    * @return the TreeExpansionListener responsible for updating the treestate
 965:    */
 966:   protected TreeExpansionListener createTreeExpansionListener()
 967:   {
 968:     return new TreeExpansionHandler();
 969:   }
 970: 
 971:   /**
 972:    * Creates the object responsible for managing what is expanded, as well as
 973:    * the size of nodes.
 974:    * 
 975:    * @return the object responsible for managing what is expanded.
 976:    */
 977:   protected AbstractLayoutCache createLayoutCache()
 978:   {
 979:     return new FixedHeightLayoutCache();
 980:   }
 981: 
 982:   /**
 983:    * Returns the renderer pane that renderer components are placed in.
 984:    * 
 985:    * @return the rendererpane that render components are placed in.
 986:    */
 987:   protected CellRendererPane createCellRendererPane()
 988:   {
 989:     return new CellRendererPane();
 990:   }
 991: 
 992:   /**
 993:    * Creates a default cell editor.
 994:    * 
 995:    * @return the default cell editor.
 996:    */
 997:   protected TreeCellEditor createDefaultCellEditor()
 998:   {
 999:     if (currentCellRenderer != null)
1000:       return new DefaultTreeCellEditor(tree,
1001:                                        (DefaultTreeCellRenderer) currentCellRenderer,
1002:                                        cellEditor);
1003:     return new DefaultTreeCellEditor(tree,
1004:                                      (DefaultTreeCellRenderer) createDefaultCellRenderer(),
1005:                                      cellEditor);
1006:   }
1007: 
1008:   /**
1009:    * Returns the default cell renderer that is used to do the stamping of each
1010:    * node.
1011:    * 
1012:    * @return the default cell renderer that is used to do the stamping of each
1013:    *         node.
1014:    */
1015:   protected TreeCellRenderer createDefaultCellRenderer()
1016:   {
1017:     return new DefaultTreeCellRenderer();
1018:   }
1019: 
1020:   /**
1021:    * Returns a listener that can update the tree when the model changes.
1022:    * 
1023:    * @return a listener that can update the tree when the model changes.
1024:    */
1025:   protected TreeModelListener createTreeModelListener()
1026:   {
1027:     return new TreeModelHandler();
1028:   }
1029: 
1030:   /**
1031:    * Uninstall all registered listeners
1032:    */
1033:   protected void uninstallListeners()
1034:   {
1035:     tree.removePropertyChangeListener(propertyChangeListener);
1036:     tree.removeFocusListener(focusListener);
1037:     tree.removeTreeSelectionListener(treeSelectionListener);
1038:     tree.removeMouseListener(mouseInputListener);
1039:     tree.removeKeyListener(keyListener);
1040:     tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1041:     tree.removeComponentListener(componentListener);
1042:     tree.removeTreeExpansionListener(treeExpansionListener);
1043: 
1044:     TreeCellEditor tce = tree.getCellEditor();
1045:     if (tce != null)
1046:       tce.removeCellEditorListener(cellEditorListener);
1047:     TreeModel tm = tree.getModel();
1048:     if (tm != null)
1049:       tm.removeTreeModelListener(treeModelListener);
1050:   }
1051: 
1052:   /**
1053:    * Uninstall all keyboard actions.
1054:    */
1055:   protected void uninstallKeyboardActions()
1056:   {
1057:   }
1058: 
1059:   /**
1060:    * Uninstall the rendererPane.
1061:    */
1062:   protected void uninstallComponents()
1063:   {
1064:     // FIXME: not implemented
1065:   }
1066: 
1067:   /**
1068:    * The vertical element of legs between nodes starts at the bottom of the
1069:    * parent node by default. This method makes the leg start below that.
1070:    * 
1071:    * @return the vertical leg buffer
1072:    */
1073:   protected int getVerticalLegBuffer()
1074:   {
1075:     // FIXME: not implemented
1076:     return 0;
1077:   }
1078: 
1079:   /**
1080:    * The horizontal element of legs between nodes starts at the right of the
1081:    * left-hand side of the child node by default. This method makes the leg end
1082:    * before that.
1083:    * 
1084:    * @return the horizontal leg buffer
1085:    */
1086:   protected int getHorizontalLegBuffer()
1087:   {
1088:     // FIXME: not implemented
1089:     return 0;
1090:   }
1091: 
1092:   /**
1093:    * Make all the nodes that are expanded in JTree expanded in LayoutCache. This
1094:    * invokes update ExpandedDescendants with the root path.
1095:    */
1096:   protected void updateLayoutCacheExpandedNodes()
1097:   {
1098:     // FIXME: not implemented
1099:   }
1100: 
1101:   /**
1102:    * Updates the expanded state of all the descendants of the <code>path</code>
1103:    * by getting the expanded descendants from the tree and forwarding to the
1104:    * tree state.
1105:    * 
1106:    * @param path
1107:    *          the path used to update the expanded states
1108:    */
1109:   protected void updateExpandedDescendants(TreePath path)
1110:   {
1111:     // FIXME: not implemented
1112:   }
1113: 
1114:   /**
1115:    * Returns a path to the last child of <code>parent</code>
1116:    * 
1117:    * @param parent
1118:    *          is the topmost path to specified
1119:    * @return a path to the last child of parent
1120:    */
1121:   protected TreePath getLastChildPath(TreePath parent)
1122:   {
1123:     return ((TreePath) parent.getLastPathComponent());
1124:   }
1125: 
1126:   /**
1127:    * Updates how much each depth should be offset by.
1128:    */
1129:   protected void updateDepthOffset()
1130:   {
1131:     // FIXME: not implemented
1132:   }
1133: 
1134:   /**
1135:    * Updates the cellEditor based on editability of the JTree that we're
1136:    * contained in. If the tree is editable but doesn't have a cellEditor, a
1137:    * basic one will be used.
1138:    */
1139:   protected void updateCellEditor()
1140:   {
1141:     if (tree.isEditable() && cellEditor == null)
1142:         setCellEditor(createDefaultCellEditor());
1143:     createdCellEditor = true;
1144:   }
1145: 
1146:   /**
1147:    * Messaged from the tree we're in when the renderer has changed.
1148:    */
1149:   protected void updateRenderer()
1150:   {
1151:     // FIXME: not implemented
1152:   }
1153: 
1154:   /**
1155:    * Resets the treeState instance based on the tree we're providing the look
1156:    * and feel for.
1157:    */
1158:   protected void configureLayoutCache()
1159:   {
1160:     treeState = createLayoutCache();
1161:   }
1162: 
1163:   /**
1164:    * Marks the cached size as being invalid, and messages the tree with
1165:    * <code>treeDidChange</code>.
1166:    */
1167:   protected void updateSize()
1168:   {
1169:     // FIXME: not implemented
1170:   }
1171: 
1172:   /**
1173:    * Updates the <code>preferredSize</code> instance variable, which is
1174:    * returned from <code>getPreferredSize()</code>. For left to right
1175:    * orientations, the size is determined from the current AbstractLayoutCache.
1176:    * For RTL orientations, the preferred size becomes the width minus the
1177:    * minimum x position.
1178:    */
1179:   protected void updateCachedPreferredSize()
1180:   {
1181:     // FIXME: not implemented
1182:   }
1183: 
1184:   /**
1185:    * Messaged from the VisibleTreeNode after it has been expanded.
1186:    * 
1187:    * @param path
1188:    *          is the path that has been expanded.
1189:    */
1190:   protected void pathWasExpanded(TreePath path)
1191:   {
1192:     // FIXME: not implemented
1193:   }
1194: 
1195:   /**
1196:    * Messaged from the VisibleTreeNode after it has collapsed
1197:    */
1198:   protected void pathWasCollapsed(TreePath path)
1199:   {
1200:     // FIXME: not implemented
1201:   }
1202: 
1203:   /**
1204:    * Install all defaults for the tree.
1205:    * 
1206:    * @param tree
1207:    *          is the JTree to install defaults for
1208:    */
1209:   protected void installDefaults(JTree tree)
1210:   {
1211:     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1212: 
1213:     tree.setFont(defaults.getFont("Tree.font"));
1214:     tree.setForeground(defaults.getColor("Tree.foreground"));
1215:     tree.setBackground(defaults.getColor("Tree.background"));
1216:     tree.setOpaque(true);
1217: 
1218:     rightChildIndent = defaults.getInt("Tree.rightChildIndent");
1219:     leftChildIndent = defaults.getInt("Tree.leftChildIndent");
1220:     setRowHeight(defaults.getInt("Tree.rowHeight"));
1221:     tree.requestFocusInWindow(false);
1222:   }
1223: 
1224:   /**
1225:    * Install all keyboard actions for this
1226:    */
1227:   protected void installKeyboardActions()
1228:   {
1229:     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1230:     InputMap focusInputMap = (InputMap) defaults.get("Tree.focusInputMap");
1231:     InputMapUIResource parentInputMap = new InputMapUIResource();
1232:     ActionMap parentActionMap = new ActionMap();
1233:     action = new TreeAction();
1234:     Object keys[] = focusInputMap.allKeys();
1235: 
1236:     for (int i = 0; i < keys.length; i++)
1237:       {
1238:         parentInputMap.put(
1239:                            KeyStroke.getKeyStroke(
1240:                                                   ((KeyStroke) keys[i]).getKeyCode(),
1241:                                                   convertModifiers(((KeyStroke) keys[i]).getModifiers())),
1242:                            (String) focusInputMap.get((KeyStroke) keys[i]));
1243: 
1244:         parentInputMap.put(
1245:                            KeyStroke.getKeyStroke(
1246:                                                   ((KeyStroke) keys[i]).getKeyCode(),
1247:                                                   ((KeyStroke) keys[i]).getModifiers()),
1248:                            (String) focusInputMap.get((KeyStroke) keys[i]));
1249: 
1250:         parentActionMap.put(
1251:                             (String) focusInputMap.get((KeyStroke) keys[i]),
1252:                             new ActionListenerProxy(
1253:                                                     action,
1254:                                                     (String) focusInputMap.get((KeyStroke) keys[i])));
1255: 
1256:       }
1257: 
1258:     parentInputMap.setParent(tree.getInputMap(
1259:                                               JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent());
1260:     parentActionMap.setParent(tree.getActionMap().getParent());
1261:     tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1262:                                                                               parentInputMap);
1263:     tree.getActionMap().setParent(parentActionMap);
1264:   }
1265: 
1266:   /**
1267:    * Converts the modifiers.
1268:    * 
1269:    * @param mod -
1270:    *          modifier to convert
1271:    * @returns the new modifier
1272:    */
1273:   private int convertModifiers(int mod)
1274:   {
1275:     if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
1276:       {
1277:         mod |= KeyEvent.SHIFT_MASK;
1278:         mod &= ~KeyEvent.SHIFT_DOWN_MASK;
1279:       }
1280:     if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
1281:       {
1282:         mod |= KeyEvent.CTRL_MASK;
1283:         mod &= ~KeyEvent.CTRL_DOWN_MASK;
1284:       }
1285:     if ((mod & KeyEvent.META_DOWN_MASK) != 0)
1286:       {
1287:         mod |= KeyEvent.META_MASK;
1288:         mod &= ~KeyEvent.META_DOWN_MASK;
1289:       }
1290:     if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
1291:       {
1292:         mod |= KeyEvent.ALT_MASK;
1293:         mod &= ~KeyEvent.ALT_DOWN_MASK;
1294:       }
1295:     if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
1296:       {
1297:         mod |= KeyEvent.ALT_GRAPH_MASK;
1298:         mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK;
1299:       }
1300:     return mod;
1301:   }
1302: 
1303:   /**
1304:    * Install all listeners for this
1305:    */
1306:   protected void installListeners()
1307:   {
1308:     tree.addPropertyChangeListener(propertyChangeListener);
1309:     tree.addFocusListener(focusListener);
1310:     tree.addTreeSelectionListener(treeSelectionListener);
1311:     tree.addMouseListener(mouseInputListener);
1312:     tree.addKeyListener(keyListener);
1313:     tree.addPropertyChangeListener(selectionModelPropertyChangeListener);
1314:     tree.addComponentListener(componentListener);
1315:     tree.addTreeExpansionListener(treeExpansionListener);
1316:     if (treeModel != null)
1317:       treeModel.addTreeModelListener(treeModelListener);
1318:   }
1319: 
1320:   /**
1321:    * Install the UI for the component
1322:    * 
1323:    * @param c
1324:    *          the component to install UI for
1325:    */
1326:   public void installUI(JComponent c)
1327:   {
1328:     super.installUI(c);
1329:     installDefaults((JTree) c);
1330:     tree = (JTree) c;
1331: 
1332:     currentCellRenderer = createDefaultCellRenderer();
1333:     rendererPane = createCellRendererPane();
1334:     createdRenderer = true;
1335: 
1336:     setCellEditor(createDefaultCellEditor());
1337:     createdCellEditor = true;
1338:     isEditing = false;
1339:     
1340:     TreeModel mod = tree.getModel();
1341:     setModel(mod);
1342:     tree.setRootVisible(true);
1343:     if (mod != null)
1344:       tree.expandPath(new TreePath(mod.getRoot()));
1345:     treeSelectionModel = tree.getSelectionModel();
1346: 
1347:     installKeyboardActions();
1348:     installListeners();
1349:     completeUIInstall();
1350:   }
1351: 
1352:   /**
1353:    * Uninstall the defaults for the tree
1354:    * 
1355:    * @param tree
1356:    *          to uninstall defaults for
1357:    */
1358:   protected void uninstallDefaults(JTree tree)
1359:   {
1360:     tree.setFont(null);
1361:     tree.setForeground(null);
1362:     tree.setBackground(null);
1363:   }
1364: 
1365:   /**
1366:    * Uninstall the UI for the component
1367:    * 
1368:    * @param c
1369:    *          the component to uninstall UI for
1370:    */
1371:   public void uninstallUI(JComponent c)
1372:   {
1373:     uninstallDefaults((JTree) c);
1374:     uninstallKeyboardActions();
1375:     uninstallListeners();
1376:     tree = null;
1377:     completeUIUninstall();
1378:   }
1379: 
1380:   /**
1381:    * Paints the specified component appropriate for the look and feel. This
1382:    * method is invoked from the ComponentUI.update method when the specified
1383:    * component is being painted. Subclasses should override this method and use
1384:    * the specified Graphics object to render the content of the component.
1385:    * 
1386:    * @param g
1387:    *          the Graphics context in which to paint
1388:    * @param c
1389:    *          the component being painted; this argument is often ignored, but
1390:    *          might be used if the UI object is stateless and shared by multiple
1391:    *          components
1392:    */
1393:   public void paint(Graphics g, JComponent c)
1394:   {
1395:     JTree tree = (JTree) c;
1396: 
1397:     TreeModel mod = tree.getModel();
1398: 
1399:     if (mod != null)
1400:       {
1401:         Object root = mod.getRoot();
1402: 
1403:         if (!tree.isRootVisible())
1404:           tree.expandPath(new TreePath(root));
1405: 
1406:         paintRecursive(g, 0, 0, 0, 0, tree, mod, root);
1407: 
1408:         if (hasControlIcons())
1409:           paintControlIcons(g, 0, 0, 0, 0, tree, mod, root);
1410:       }
1411:   }
1412: 
1413:   /**
1414:    * Ensures that the rows identified by beginRow through endRow are visible.
1415:    * 
1416:    * @param beginRow
1417:    *          is the first row
1418:    * @param endRow
1419:    *          is the last row
1420:    */
1421:   protected void ensureRowsAreVisible(int beginRow, int endRow)
1422:   {
1423:     // FIXME: not implemented
1424:   }
1425: 
1426:   /**
1427:    * Sets the preferred minimum size.
1428:    * 
1429:    * @param newSize
1430:    *          is the new preferred minimum size.
1431:    */
1432:   public void setPreferredMinSize(Dimension newSize)
1433:   {
1434:     // FIXME: not implemented
1435:   }
1436: 
1437:   /**
1438:    * Gets the preferred minimum size.
1439:    * 
1440:    * @returns the preferred minimum size.
1441:    */
1442:   public Dimension getPreferredMinSize()
1443:   {
1444:     // FIXME: not implemented
1445:     return null;
1446:   }
1447: 
1448:   /**
1449:    * Returns the preferred size to properly display the tree, this is a cover
1450:    * method for getPreferredSize(c, false).
1451:    * 
1452:    * @param c
1453:    *          the component whose preferred size is being queried; this argument
1454:    *          is often ignored but might be used if the UI object is stateless
1455:    *          and shared by multiple components
1456:    * @return the preferred size
1457:    */
1458:   public Dimension getPreferredSize(JComponent c)
1459:   {
1460:     return getPreferredSize(c, false);
1461:   }
1462: 
1463:   /**
1464:    * Returns the preferred size to represent the tree in c. If checkConsistancy
1465:    * is true, checkConsistancy is messaged first.
1466:    * 
1467:    * @param c
1468:    *          the component whose preferred size is being queried.
1469:    * @param checkConsistancy
1470:    *          if true must check consistancy
1471:    * @return the preferred size
1472:    */
1473:   public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1474:   {
1475:     // FIXME: checkConsistancy not implemented, c not used
1476:     TreeModel model = tree.getModel();
1477:     int maxWidth = 0;
1478:     int count = 0;
1479:     if (model != null)
1480:       {
1481:         Object node = model.getRoot();
1482:         if (node != null)
1483:           {
1484:             maxWidth = (int) (getCellBounds(0, 0, node).getWidth());
1485:             while (node != null)
1486:               {
1487:                 count++;
1488:                 Object nextNode = getNextVisibleNode(node);
1489:                 if (nextNode != null)
1490:                   maxWidth = Math.max(maxWidth,
1491:                                       (int) (getCellBounds(0, 0, nextNode).getWidth()));
1492:                 node = nextNode;
1493:               }
1494:           }
1495:       }
1496:     return new Dimension(maxWidth, (getRowHeight() * count));
1497:   }
1498: 
1499:   /**
1500:    * Returns the minimum size for this component. Which will be the min
1501:    * preferred size or (0,0).
1502:    * 
1503:    * @param c
1504:    *          the component whose min size is being queried.
1505:    * @returns the preferred size or null
1506:    */
1507:   public Dimension getMinimumSize(JComponent c)
1508:   {
1509:     // FIXME: not implemented
1510:     return getPreferredSize(c);
1511:   }
1512: 
1513:   /**
1514:    * Returns the maximum size for the component, which will be the preferred
1515:    * size if the instance is currently in JTree or (0,0).
1516:    * 
1517:    * @param c
1518:    *          the component whose preferred size is being queried
1519:    * @return the max size or null
1520:    */
1521:   public Dimension getMaximumSize(JComponent c)
1522:   {
1523:     // FIXME: not implemented
1524:     return getPreferredSize(c);
1525:   }
1526: 
1527:   /**
1528:    * Messages to stop the editing session. If the UI the receiver is providing
1529:    * the look and feel for returns true from
1530:    * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked
1531:    * on the current editor. Then completeEditing will be messaged with false,
1532:    * true, false to cancel any lingering editing.
1533:    */
1534:   protected void completeEditing()
1535:   {
1536:     completeEditing(false, true, false);
1537:   }
1538: 
1539:   /**
1540:    * Stops the editing session. If messageStop is true, the editor is messaged
1541:    * with stopEditing, if messageCancel is true the editor is messaged with
1542:    * cancelEditing. If messageTree is true, the treeModel is messaged with
1543:    * valueForPathChanged.
1544:    * 
1545:    * @param messageStop
1546:    *          message to stop editing
1547:    * @param messageCancel
1548:    *          message to cancel editing
1549:    * @param messageTree
1550:    *          message to treeModel
1551:    */
1552:   protected void completeEditing(boolean messageStop, boolean messageCancel,
1553:                                  boolean messageTree)
1554:   {
1555:     if (messageStop)
1556:       {
1557:         getCellEditor().stopCellEditing();
1558:         stopEditingInCompleteEditing = true;
1559:       }
1560: 
1561:     if (messageCancel)
1562:       {
1563:         getCellEditor().cancelCellEditing();
1564:         stopEditingInCompleteEditing = true;
1565:       }
1566: 
1567:     if (messageTree)
1568:       tree.getModel().valueForPathChanged(tree.getLeadSelectionPath(), newVal);
1569:   }
1570: 
1571:   /**
1572:    * Will start editing for node if there is a cellEditor and shouldSelectCall
1573:    * returns true. This assumes that path is valid and visible.
1574:    * 
1575:    * @param path
1576:    *          is the path to start editing
1577:    * @param event
1578:    *          is the MouseEvent performed on the path
1579:    * @return true if successful
1580:    */
1581:   protected boolean startEditing(TreePath path, MouseEvent event)
1582:   {
1583:     int x;
1584:     int y;
1585:     if (event == null)
1586:       {
1587:         Rectangle bounds = getPathBounds(tree, path);
1588:         x = bounds.x;
1589:         y = bounds.y;
1590:       }
1591:     else
1592:       {
1593:         x = event.getX();
1594:         y = event.getY();
1595:       }
1596: 
1597:     updateCellEditor();
1598:     TreeCellEditor ed = getCellEditor();
1599:     if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event))
1600:       {
1601:         editingPath = path;
1602:         editingRow = tree.getRowForPath(editingPath);
1603:         Object val = editingPath.getLastPathComponent();
1604:         cellEditor.addCellEditorListener(cellEditorListener);
1605:         stopEditingInCompleteEditing = false;
1606:         boolean expanded = tree.isExpanded(editingPath);
1607:         isEditing = true;
1608:         editingComponent = ed.getTreeCellEditorComponent(tree, val, true,
1609:                                                          expanded,
1610:                                                          isLeaf(editingRow),
1611:                                                          editingRow);
1612:         editingComponent.getParent().setVisible(true);
1613:         editingComponent.getParent().validate();
1614:         tree.add(editingComponent.getParent());
1615:         editingComponent.getParent().validate();
1616:         ((JTextField) editingComponent).requestFocusInWindow(false);
1617:         editorTimer.start();
1618:         return true;
1619:       }
1620:     return false;
1621:   }
1622: 
1623:   /**
1624:    * If the <code>mouseX</code> and <code>mouseY</code> are in the expand or
1625:    * collapse region of the row, this will toggle the row.
1626:    * 
1627:    * @param path
1628:    *          the path we are concerned with
1629:    * @param mouseX
1630:    *          is the cursor's x position
1631:    * @param mouseY
1632:    *          is the cursor's y position
1633:    */
1634:   protected void checkForClickInExpandControl(TreePath path, int mouseX,
1635:                                               int mouseY)
1636:   {
1637:     // FIXME: not implemented
1638:   }
1639: 
1640:   /**
1641:    * Returns true if the <code>mouseX</code> and <code>mouseY</code> fall in
1642:    * the area of row that is used to expand/collpse the node and the node at row
1643:    * does not represent a leaf.
1644:    * 
1645:    * @param path
1646:    *          the path we are concerned with
1647:    * @param mouseX
1648:    *          is the cursor's x position
1649:    * @param mouseY
1650:    *          is the cursor's y position
1651:    * @return true if the <code>mouseX</code> and <code>mouseY</code> fall in
1652:    *         the area of row that is used to expand/collpse the node and the
1653:    *         node at row does not represent a leaf.
1654:    */
1655:   protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1656:                                               int mouseY)
1657:   {
1658:     // FIXME: not implemented
1659:     return false;
1660:   }
1661: 
1662:   /**
1663:    * Messaged when the user clicks the particular row, this invokes
1664:    * toggleExpandState.
1665:    * 
1666:    * @param path
1667:    *          the path we are concerned with
1668:    * @param mouseX
1669:    *          is the cursor's x position
1670:    * @param mouseY
1671:    *          is the cursor's y position
1672:    */
1673:   protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1674:   {
1675:     // FIXME: not implemented
1676:   }
1677: 
1678:   /**
1679:    * Expands path if it is not expanded, or collapses row if it is expanded. If
1680:    * expanding a path and JTree scroll on expand, ensureRowsAreVisible is
1681:    * invoked to scroll as many of the children to visible as possible (tries to
1682:    * scroll to last visible descendant of path).
1683:    * 
1684:    * @param path
1685:    *          the path we are concerned with
1686:    */
1687:   protected void toggleExpandState(TreePath path)
1688:   {
1689:     // FIXME: not implemented
1690:   }
1691: 
1692:   /**
1693:    * Returning true signifies a mouse event on the node should toggle the
1694:    * selection of only the row under the mouse.
1695:    * 
1696:    * @param event
1697:    *          is the MouseEvent performed on the row.
1698:    * @return true signifies a mouse event on the node should toggle the
1699:    *         selection of only the row under the mouse.
1700:    */
1701:   protected boolean isToggleSelectionEvent(MouseEvent event)
1702:   {
1703:     // FIXME: not implemented
1704:     return false;
1705:   }
1706: 
1707:   /**
1708:    * Returning true signifies a mouse event on the node should select from the
1709:    * anchor point.
1710:    * 
1711:    * @param event
1712:    *          is the MouseEvent performed on the node.
1713:    * @return true signifies a mouse event on the node should select from the
1714:    *         anchor point.
1715:    */
1716:   protected boolean isMultiSelectEvent(MouseEvent event)
1717:   {
1718:     // FIXME: not implemented
1719:     return false;
1720:   }
1721: 
1722:   /**
1723:    * Returning true indicates the row under the mouse should be toggled based on
1724:    * the event. This is invoked after checkForClickInExpandControl, implying the
1725:    * location is not in the expand (toggle) control.
1726:    * 
1727:    * @param event
1728:    *          is the MouseEvent performed on the row.
1729:    * @return true indicates the row under the mouse should be toggled based on
1730:    *         the event.
1731:    */
1732:   protected boolean isToggleEvent(MouseEvent event)
1733:   {
1734:     // FIXME: not implemented
1735:     return false;
1736:   }
1737: 
1738:   /**
1739:    * Messaged to update the selection based on a MouseEvent over a particular
1740:    * row. If the even is a toggle selection event, the row is either selected,
1741:    * or deselected. If the event identifies a multi selection event, the
1742:    * selection is updated from the anchor point. Otherwise, the row is selected,
1743:    * and if the even specified a toggle event the row is expanded/collapsed.
1744:    * 
1745:    * @param path
1746:    *          is the path selected for an event
1747:    * @param event
1748:    *          is the MouseEvent performed on the path.
1749:    */
1750:   protected void selectPathForEvent(TreePath path, MouseEvent event)
1751:   {
1752:     // FIXME: not implemented
1753:   }
1754: 
1755:   /**
1756:    * Returns true if the node at <code>row</code> is a leaf.
1757:    * 
1758:    * @param row
1759:    *          is the row we are concerned with.
1760:    * @return true if the node at <code>row</code> is a leaf.
1761:    */
1762:   protected boolean isLeaf(int row)
1763:   {
1764:     TreePath pathForRow = getPathForRow(tree, row);
1765:     if (pathForRow == null)
1766:       return true;
1767: 
1768:     Object node = pathForRow.getLastPathComponent();
1769:     return tree.getModel().isLeaf(node);
1770:   }
1771: 
1772:   /**
1773:    * This class implements the actions that we want to happen when specific keys
1774:    * are pressed for the JTree. The actionPerformed method is called when a key
1775:    * that has been registered for the JTree is received.
1776:    */
1777:   class TreeAction
1778:     extends AbstractAction
1779:   {
1780: 
1781:     /**
1782:      * What to do when this action is called.
1783:      * 
1784:      * @param e
1785:      *          the ActionEvent that caused this action.
1786:      */
1787:     public void actionPerformed(ActionEvent e)
1788:     {
1789:       TreePath lead = tree.getLeadSelectionPath();
1790: 
1791:       if (e.getActionCommand().equals("selectPreviousChangeLead")
1792:           || e.getActionCommand().equals("selectPreviousExtendSelection")
1793:           || e.getActionCommand().equals("selectPrevious")
1794:           || e.getActionCommand().equals("selectNext")
1795:           || e.getActionCommand().equals("selectNextExtendSelection")
1796:           || e.getActionCommand().equals("selectNextChangeLead"))
1797:         (new TreeIncrementAction(0, "")).actionPerformed(e);
1798:       else if (e.getActionCommand().equals("selectParent")
1799:                || e.getActionCommand().equals("selectChild"))
1800:         (new TreeTraverseAction(0, "")).actionPerformed(e);
1801:       else if (e.getActionCommand().equals("selectAll"))
1802:         {
1803:           TreePath[] paths = new TreePath[tree.getRowCount()];
1804: 
1805:           Object curr = getNextVisibleNode(tree.getModel().getRoot());
1806:           int i = 0;
1807:           while (curr != null && i < paths.length)
1808:             {
1809:               paths[i] = new TreePath(getPathToRoot(curr, 0));
1810:               i++;
1811:             }
1812: 
1813:           tree.addSelectionPaths(paths);
1814:         }
1815:       else if (e.getActionCommand().equals("startEditing"))
1816:         tree.startEditingAtPath(lead);
1817:       else if (e.getActionCommand().equals("toggle"))
1818:         {
1819:           if (tree.isEditing())
1820:               tree.stopEditing();
1821:           else
1822:             {
1823:               Object last = lead.getLastPathComponent();
1824:               TreePath path = new TreePath(getPathToRoot(last, 0));
1825:               if (!tree.getModel().isLeaf(last))
1826:                 {
1827:                   if (tree.isExpanded(path))
1828:                     tree.collapsePath(path);
1829:                   else
1830:                     tree.expandPath(path);
1831:                 }
1832:             }
1833:         }
1834:       else if (e.getActionCommand().equals("clearSelection"))
1835:         tree.clearSelection();
1836: 
1837:       if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
1838:         tree.cancelEditing();
1839: 
1840:       tree.scrollPathToVisible(lead);
1841:     }
1842:   }
1843: 
1844:   /**
1845:    * This class is used to mimic the behaviour of the JDK when registering
1846:    * keyboard actions. It is the same as the private class used in JComponent
1847:    * for the same reason. This class receives an action event and dispatches it
1848:    * to the true receiver after altering the actionCommand property of the
1849:    * event.
1850:    */
1851:   private static class ActionListenerProxy
1852:     extends AbstractAction
1853:   {
1854:     ActionListener target;
1855: 
1856:     String bindingCommandName;
1857: 
1858:     public ActionListenerProxy(ActionListener li, String cmd)
1859:     {
1860:       target = li;
1861:       bindingCommandName = cmd;
1862:     }
1863: 
1864:     public void actionPerformed(ActionEvent e)
1865:     {
1866:       ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
1867:                                                  bindingCommandName,
1868:                                                  e.getModifiers());
1869: 
1870:       target.actionPerformed(derivedEvent);
1871:     }
1872:   }
1873: 
1874:   /**
1875:    * The timer that updates the editor component.
1876:    */
1877:   private class EditorUpdateTimer
1878:     extends Timer
1879:     implements ActionListener
1880:   {
1881:     /**
1882:      * Creates a new EditorUpdateTimer object with a default delay of 0.3
1883:      * seconds.
1884:      */
1885:     public EditorUpdateTimer()
1886:     {
1887:       super(300, null);
1888:       addActionListener(this);
1889:     }
1890: 
1891:     /**
1892:      * Lets the caret blink and repaints the table.
1893:      */
1894:     public void actionPerformed(ActionEvent ev)
1895:     {
1896:       Caret c = ((JTextField) editingComponent).getCaret();
1897:       if (c != null)
1898:         c.setVisible(!c.isVisible());
1899:       tree.repaint();
1900:     }
1901: 
1902:     /**
1903:      * Updates the blink delay according to the current caret.
1904:      */
1905:     public void update()
1906:     {
1907:       stop();
1908:       Caret c = ((JTextField) editingComponent).getCaret();
1909:       if (c != null)
1910:         {
1911:           setDelay(c.getBlinkRate());
1912:           if (((JTextField) editingComponent).isEditable())
1913:             start();
1914:           else
1915:             c.setVisible(false);
1916:         }
1917:     }
1918:   }
1919: 
1920:   /**
1921:    * Updates the preferred size when scrolling, if necessary.
1922:    */
1923:   public class ComponentHandler
1924:     extends ComponentAdapter
1925:     implements ActionListener
1926:   {
1927:     /**
1928:      * Timer used when inside a scrollpane and the scrollbar is adjusting
1929:      */
1930:     protected Timer timer;
1931: 
1932:     /** ScrollBar that is being adjusted */
1933:     protected JScrollBar scrollBar;
1934: 
1935:     /**
1936:      * Constructor
1937:      */
1938:     public ComponentHandler()
1939:     {
1940:     }
1941: 
1942:     /**
1943:      * Invoked when the component's position changes.
1944:      * 
1945:      * @param e
1946:      *          the event that occurs when moving the component
1947:      */
1948:     public void componentMoved(ComponentEvent e)
1949:     {
1950:     }
1951: 
1952:     /**
1953:      * Creats, if necessary, and starts a Timer to check if needed to resize the
1954:      * bounds
1955:      */
1956:     protected void startTimer()
1957:     {
1958:     }
1959: 
1960:     /**
1961:      * Returns the JScrollPane housing the JTree, or null if one isn't found.
1962:      * 
1963:      * @return JScrollPane housing the JTree, or null if one isn't found.
1964:      */
1965:     protected JScrollPane getScrollPane()
1966:     {
1967:       return null;
1968:     }
1969: 
1970:     /**
1971:      * Public as a result of Timer. If the scrollBar is null, or not adjusting,
1972:      * this stops the timer and updates the sizing.
1973:      * 
1974:      * @param ae
1975:      *          is the action performed
1976:      */
1977:     public void actionPerformed(ActionEvent ae)
1978:     {
1979:     }
1980:   }// ComponentHandler
1981: 
1982:   /**
1983:    * Listener responsible for getting cell editing events and updating the tree
1984:    * accordingly.
1985:    */
1986:   public class CellEditorHandler
1987:     implements CellEditorListener
1988:   {
1989:     /**
1990:      * Constructor
1991:      */
1992:     public CellEditorHandler()
1993:     {
1994:     }
1995: 
1996:     /**
1997:      * Messaged when editing has stopped in the tree. Tells the listeners
1998:      * editing has stopped.
1999:      * 
2000:      * @param e
2001:      *          is the notification event
2002:      */
2003:     public void editingStopped(ChangeEvent e)
2004:     {
2005:       editingPath = null;
2006:       editingRow = -1;
2007:       stopEditingInCompleteEditing = false;
2008:       if (editingComponent != null)
2009:         {
2010:           tree.remove(editingComponent.getParent());
2011:           editingComponent = null;
2012:         }
2013:       if (cellEditor != null)
2014:         {
2015:           newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText();
2016:           completeEditing(false, false, true);
2017:           if (cellEditor instanceof DefaultTreeCellEditor)
2018:             tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2019:           cellEditor.removeCellEditorListener(cellEditorListener);
2020:           setCellEditor(null);
2021:           createdCellEditor = false;
2022:         }
2023:       isEditing = false;
2024:       tree.requestFocusInWindow(false);
2025:       editorTimer.stop();
2026:     }
2027: 
2028:     /**
2029:      * Messaged when editing has been canceled in the tree. This tells the
2030:      * listeners the editor has canceled editing.
2031:      * 
2032:      * @param e
2033:      *          is the notification event
2034:      */
2035:     public void editingCanceled(ChangeEvent e)
2036:     {
2037:       editingPath = null;
2038:       editingRow = -1;
2039:       stopEditingInCompleteEditing = false;
2040:       if (editingComponent != null)
2041:         tree.remove(editingComponent.getParent());
2042:       editingComponent = null;
2043:       if (cellEditor != null)
2044:         {
2045:           if (cellEditor instanceof DefaultTreeCellEditor)
2046:             tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2047:           cellEditor.removeCellEditorListener(cellEditorListener);
2048:           setCellEditor(null);
2049:           createdCellEditor = false;
2050:         }
2051:       tree.requestFocusInWindow(false);
2052:       editorTimer.stop();
2053:       isEditing = false;
2054:       tree.repaint();
2055:     }
2056:   }// CellEditorHandler
2057: 
2058:   /**
2059:    * Repaints the lead selection row when focus is lost/grained.
2060:    */
2061:   public class FocusHandler
2062:     implements FocusListener
2063:   {
2064:     /**
2065:      * Constructor
2066:      */
2067:     public FocusHandler()
2068:     {
2069:     }
2070: 
2071:     /**
2072:      * Invoked when focus is activated on the tree we're in, redraws the lead
2073:      * row. Invoked when a component gains the keyboard focus.
2074:      * 
2075:      * @param e
2076:      *          is the focus event that is activated
2077:      */
2078:     public void focusGained(FocusEvent e)
2079:     {
2080:     }
2081: 
2082:     /**
2083:      * Invoked when focus is deactivated on the tree we're in, redraws the lead
2084:      * row. Invoked when a component loses the keyboard focus.
2085:      * 
2086:      * @param e
2087:      *          is the focus event that is deactivated
2088:      */
2089:     public void focusLost(FocusEvent e)
2090:     {
2091:     }
2092:   }// FocusHandler
2093: 
2094:   /**
2095:    * This is used to get multiple key down events to appropriately genereate
2096:    * events.
2097:    */
2098:   public class KeyHandler
2099:     extends KeyAdapter
2100:   {
2101:     /** Key code that is being generated for. */
2102:     protected Action repeatKeyAction;
2103: 
2104:     /** Set to true while keyPressed is active */
2105:     protected boolean isKeyDown;
2106: 
2107:     /**
2108:      * Constructor
2109:      */
2110:     public KeyHandler()
2111:     {
2112:     }
2113: 
2114:     /**
2115:      * Invoked when a key has been typed. Moves the keyboard focus to the first
2116:      * element whose first letter matches the alphanumeric key pressed by the
2117:      * user. Subsequent same key presses move the keyboard focus to the next
2118:      * object that starts with the same letter.
2119:      * 
2120:      * @param e
2121:      *          the key typed
2122:      */
2123:     public void keyTyped(KeyEvent e)
2124:     {
2125:     }
2126: 
2127:     /**
2128:      * Invoked when a key has been pressed.
2129:      * 
2130:      * @param e
2131:      *          the key pressed
2132:      */
2133:     public void keyPressed(KeyEvent e)
2134:     {
2135:     }
2136: 
2137:     /**
2138:      * Invoked when a key has been released
2139:      * 
2140:      * @param e
2141:      *          the key released
2142:      */
2143:     public void keyReleased(KeyEvent e)
2144:     {
2145:     }
2146:   }// KeyHandler
2147: 
2148:   /**
2149:    * MouseListener is responsible for updating the selection based on mouse
2150:    * events.
2151:    */
2152:   public class MouseHandler
2153:     extends MouseAdapter
2154:     implements MouseMotionListener
2155:   {
2156:     /**
2157:      * Constructor
2158:      */
2159:     public MouseHandler()
2160:     {
2161:     }
2162: 
2163:     /**
2164:      * Invoked when a mouse button has been pressed on a component.
2165:      * 
2166:      * @param e
2167:      *          is the mouse event that occured
2168:      */
2169:     public void mousePressed(MouseEvent e)
2170:     {
2171:     }
2172: 
2173:     /**
2174:      * Invoked when a mouse button is pressed on a component and then dragged.
2175:      * MOUSE_DRAGGED events will continue to be delivered to the component where
2176:      * the drag originated until the mouse button is released (regardless of
2177:      * whether the mouse position is within the bounds of the component).
2178:      * 
2179:      * @param e
2180:      *          is the mouse event that occured
2181:      */
2182:     public void mouseDragged(MouseEvent e)
2183:     {
2184:     }
2185: 
2186:     /**
2187:      * Invoked when the mouse button has been moved on a component (with no
2188:      * buttons no down).
2189:      * 
2190:      * @param e
2191:      *          the mouse event that occured
2192:      */
2193:     public void mouseMoved(MouseEvent e)
2194:     {
2195:     }
2196: 
2197:     /**
2198:      * Invoked when a mouse button has been released on a component.
2199:      * 
2200:      * @param e
2201:      *          is the mouse event that occured
2202:      */
2203:     public void mouseReleased(MouseEvent e)
2204:     {
2205:     }
2206:   }// MouseHandler
2207: 
2208:   /**
2209:    * MouseInputHandler handles passing all mouse events, including mouse motion
2210:    * events, until the mouse is released to the destination it is constructed
2211:    * with.
2212:    */
2213:   public class MouseInputHandler
2214:     implements MouseInputListener
2215:   {
2216:     /** Source that events are coming from */
2217:     protected Component source;
2218: 
2219:     /** Destination that receives all events. */
2220:     protected Component destination;
2221: 
2222:     /**
2223:      * Constructor
2224:      * 
2225:      * @param source
2226:      *          that events are coming from
2227:      * @param destination
2228:      *          that receives all events
2229:      * @param e
2230:      *          is the event received
2231:      */
2232:     public MouseInputHandler(Component source, Component destination,
2233:                              MouseEvent e)
2234:     {
2235:     }
2236: 
2237:     /**
2238:      * Invoked when the mouse button has been clicked (pressed and released) on
2239:      * a component.
2240:      * 
2241:      * @param e
2242:      *          mouse event that occured
2243:      */
2244:     public void mouseClicked(MouseEvent e)
2245:     {
2246:     }
2247: 
2248:     /**
2249:      * Invoked when a mouse button has been pressed on a component.
2250:      * 
2251:      * @param e
2252:      *          mouse event that occured
2253:      */
2254:     public void mousePressed(MouseEvent e)
2255:     {
2256:       Point click = e.getPoint();
2257:       int row = Math.round(click.y / getRowHeight());
2258:       TreePath path = getClosestPathForLocation(tree, click.x, click.y);
2259: 
2260:       if (path != null)
2261:         {
2262:           boolean inBounds = false;
2263:           boolean cntlClick = false;
2264:           Rectangle bounds = getPathBounds(tree, path);
2265: 
2266:           bounds.x -= rightChildIndent - 4;
2267:           bounds.width += rightChildIndent + 4;
2268: 
2269:           if (bounds.contains(click.x, click.y))
2270:             inBounds = true;
2271:           else if (hasControlIcons()
2272:                    && (click.x < (bounds.x - rightChildIndent + 5) && 
2273:                        click.x > (bounds.x - rightChildIndent - 5)))
2274:             cntlClick = true;
2275: 
2276:           if ((inBounds || cntlClick) && tree.isVisible(path))
2277:             {
2278:               selectPath(tree, path);
2279: 
2280:               if ((e.getClickCount() == 2 || cntlClick) && !isLeaf(row))
2281:                 {
2282:                   if (tree.isExpanded(path))
2283:                     tree.collapsePath(path);
2284:                   else
2285:                     tree.expandPath(path);
2286:                 }
2287: 
2288:               if (!cntlClick && tree.isEditable())
2289:                 startEditing(path, e);
2290:             }
2291:         }
2292:     }
2293: 
2294:     /**
2295:      * Invoked when a mouse button has been released on a component.
2296:      * 
2297:      * @param e
2298:      *          mouse event that occured
2299:      */
2300:     public void mouseReleased(MouseEvent e)
2301:     {
2302:     }
2303: 
2304:     /**
2305:      * Invoked when the mouse enters a component.
2306:      * 
2307:      * @param e
2308:      *          mouse event that occured
2309:      */
2310:     public void mouseEntered(MouseEvent e)
2311:     {
2312:     }
2313: 
2314:     /**
2315:      * Invoked when the mouse exits a component.
2316:      * 
2317:      * @param e
2318:      *          mouse event that occured
2319:      */
2320:     public void mouseExited(MouseEvent e)
2321:     {
2322:     }
2323: 
2324:     /**
2325:      * Invoked when a mouse button is pressed on a component and then dragged.
2326:      * MOUSE_DRAGGED events will continue to be delivered to the component where
2327:      * the drag originated until the mouse button is released (regardless of
2328:      * whether the mouse position is within the bounds of the component).
2329:      * 
2330:      * @param e
2331:      *          mouse event that occured
2332:      */
2333:     public void mouseDragged(MouseEvent e)
2334:     {
2335:     }
2336: 
2337:     /**
2338:      * Invoked when the mouse cursor has been moved onto a component but no
2339:      * buttons have been pushed.
2340:      * 
2341:      * @param e
2342:      *          mouse event that occured
2343:      */
2344:     public void mouseMoved(MouseEvent e)
2345:     {
2346:     }
2347: 
2348:     /**
2349:      * Removes event from the source
2350:      */
2351:     protected void removeFromSource()
2352:     {
2353:     }
2354:   }// MouseInputHandler
2355: 
2356:   /**
2357:    * Class responsible for getting size of node, method is forwarded to
2358:    * BasicTreeUI method. X location does not include insets, that is handled in
2359:    * getPathBounds.
2360:    */
2361:   public class NodeDimensionsHandler
2362:     extends AbstractLayoutCache.NodeDimensions
2363:   {
2364:     /**
2365:      * Constructor
2366:      */
2367:     public NodeDimensionsHandler()
2368:     {
2369:     }
2370: 
2371:     /**
2372:      * Responsible for getting the size of a particular node.
2373:      * 
2374:      * @param value
2375:      *          the value to be represented
2376:      * @param row
2377:      *          row being queried
2378:      * @param depth
2379:      *          the depth of the row
2380:      * @param expanded
2381:      *          true if row is expanded
2382:      * @param size
2383:      *          a Rectangle containing the size needed to represent value
2384:      * @return containing the node dimensions, or null if node has no dimension
2385:      */
2386:     public Rectangle getNodeDimensions(Object value, int row, int depth,
2387:                                        boolean expanded, Rectangle size)
2388:     {
2389:       return null;
2390:     }
2391: 
2392:     /**
2393:      * Returns the amount to indent the given row
2394:      * 
2395:      * @return amount to indent the given row.
2396:      */
2397:     protected int getRowX(int row, int depth)
2398:     {
2399:       return 0;
2400:     }
2401:   }// NodeDimensionsHandler
2402: 
2403:   /**
2404:    * PropertyChangeListener for the tree. Updates the appropriate varaible, or
2405:    * TreeState, based on what changes.
2406:    */
2407:   public class PropertyChangeHandler
2408:     implements PropertyChangeListener
2409:   {
2410: 
2411:     /**
2412:      * Constructor
2413:      */
2414:     public PropertyChangeHandler()
2415:     {
2416:     }
2417: 
2418:     /**
2419:      * This method gets called when a bound property is changed.
2420:      * 
2421:      * @param event
2422:      *          A PropertyChangeEvent object describing the event source and the
2423:      *          property that has changed.
2424:      */
2425:     public void propertyChange(PropertyChangeEvent event)
2426:     {
2427:     }
2428:   }// PropertyChangeHandler
2429: 
2430:   /**
2431:    * Listener on the TreeSelectionModel, resets the row selection if any of the
2432:    * properties of the model change.
2433:    */
2434:   public class SelectionModelPropertyChangeHandler
2435:     implements PropertyChangeListener
2436:   {
2437: 
2438:     /**
2439:      * Constructor
2440:      */
2441:     public SelectionModelPropertyChangeHandler()
2442:     {
2443:     }
2444: 
2445:     /**
2446:      * This method gets called when a bound property is changed.
2447:      * 
2448:      * @param event
2449:      *          A PropertyChangeEvent object describing the event source and the
2450:      *          property that has changed.
2451:      */
2452:     public void propertyChange(PropertyChangeEvent event)
2453:     {
2454:     }
2455:   }// SelectionModelPropertyChangeHandler
2456: 
2457:   /**
2458:    * ActionListener that invokes cancelEditing when action performed.
2459:    */
2460:   public class TreeCancelEditingAction
2461:     extends AbstractAction
2462:   {
2463: 
2464:     /**
2465:      * Constructor
2466:      */
2467:     public TreeCancelEditingAction()
2468:     {
2469:     }
2470: 
2471:     /**
2472:      * Invoked when an action occurs.
2473:      * 
2474:      * @param e
2475:      *          event that occured
2476:      */
2477:     public void actionPerformed(ActionEvent e)
2478:     {
2479:     }
2480: 
2481:     /**
2482:      * Returns true if the action is enabled.
2483:      * 
2484:      * @return true if the action is enabled, false otherwise
2485:      */
2486:     public boolean isEnabled()
2487:     {
2488:       return false;
2489:     }
2490:   }// TreeCancelEditingAction
2491: 
2492:   /**
2493:    * Updates the TreeState in response to nodes expanding/collapsing.
2494:    */
2495:   public class TreeExpansionHandler
2496:     implements TreeExpansionListener
2497:   {
2498: 
2499:     /**
2500:      * Constructor
2501:      */
2502:     public TreeExpansionHandler()
2503:     {
2504:     }
2505: 
2506:     /**
2507:      * Called whenever an item in the tree has been expanded.
2508:      * 
2509:      * @param event
2510:      *          is the event that occured
2511:      */
2512:     public void treeExpanded(TreeExpansionEvent event)
2513:     {
2514:       tree.repaint();
2515:     }
2516: 
2517:     /**
2518:      * Called whenever an item in the tree has been collapsed.
2519:      * 
2520:      * @param event
2521:      *          is the event that occured
2522:      */
2523:     public void treeCollapsed(TreeExpansionEvent event)
2524:     {
2525:       tree.repaint();
2526:     }
2527:   }// TreeExpansionHandler
2528: 
2529:   /**
2530:    * TreeHomeAction is used to handle end/home actions. Scrolls either the first
2531:    * or last cell to be visible based on direction.
2532:    */
2533:   public class TreeHomeAction
2534:     extends AbstractAction
2535:   {
2536: 
2537:     /** direction is either home or end */
2538:     protected int direction;
2539: 
2540:     /**
2541:      * Constructor
2542:      * 
2543:      * @param direction -
2544:      *          it is home or end
2545:      * @param name
2546:      *          is the name of the direction
2547:      */
2548:     public TreeHomeAction(int direction, String name)
2549:     {
2550:     }
2551: 
2552:     /**
2553:      * Invoked when an action occurs.
2554:      * 
2555:      * @param e
2556:      *          is the event that occured
2557:      */
2558:     public void actionPerformed(ActionEvent e)
2559:     {
2560:     }
2561: 
2562:     /**
2563:      * Returns true if the action is enabled.
2564:      * 
2565:      * @return true if the action is enabled.
2566:      */
2567:     public boolean isEnabled()
2568:     {
2569:       return false;
2570:     }
2571:   }// TreeHomeAction
2572: 
2573:   /**
2574:    * TreeIncrementAction is used to handle up/down actions. Selection is moved
2575:    * up or down based on direction.
2576:    */
2577:   public class TreeIncrementAction
2578:     extends AbstractAction
2579:   {
2580: 
2581:     /** Specifies the direction to adjust the selection by. */
2582:     protected int direction;
2583: 
2584:     /**
2585:      * Constructor
2586:      * 
2587:      * @param direction
2588:      *          up or down
2589:      * @param name
2590:      *          is the name of the direction
2591:      */
2592:     public TreeIncrementAction(int direction, String name)
2593:     {
2594:     }
2595: 
2596:     /**
2597:      * Invoked when an action occurs.
2598:      * 
2599:      * @param e
2600:      *          is the event that occured
2601:      */
2602:     public void actionPerformed(ActionEvent e)
2603:     {
2604:       Object last = tree.getLeadSelectionPath().getLastPathComponent();
2605: 
2606:       if (e.getActionCommand().equals("selectPreviousChangeLead"))
2607:         {
2608:           Object prev = getPreviousVisibleNode(last);
2609: 
2610:           if (prev != null)
2611:             {
2612:               TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2613:               selectPath(tree, new TreePath(getPathToRoot(prev, 0)));
2614:               tree.setLeadSelectionPath(newPath);
2615:             }
2616:         }
2617:       else if (e.getActionCommand().equals("selectPreviousExtendSelection"))
2618:         {
2619:           Object prev = getPreviousVisibleNode(last);
2620:           if (prev != null)
2621:             {
2622:               TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2623:               tree.addSelectionPath(newPath);
2624:               tree.setLeadSelectionPath(newPath);
2625:             }
2626:         }
2627:       else if (e.getActionCommand().equals("selectPrevious"))
2628:         {
2629:           Object prev = getPreviousVisibleNode(last);
2630:           if (prev != null)
2631:             {
2632:               TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2633:               selectPath(tree, new TreePath(getPathToRoot(prev, 0)));
2634:             }
2635:         }
2636:       else if (e.getActionCommand().equals("selectNext"))
2637:         {
2638:           Object next = getNextVisibleNode(last);
2639:           if (next != null)
2640:             {
2641:               TreePath newPath = new TreePath(getPathToRoot(next, 0));
2642:               selectPath(tree, newPath);
2643:             }
2644:         }
2645:       else if (e.getActionCommand().equals("selectNextExtendSelection"))
2646:         {
2647:           Object next = getNextVisibleNode(last);
2648:           if (next != null)
2649:             {
2650:               TreePath newPath = new TreePath(getPathToRoot(next, 0));
2651:               tree.addSelectionPath(newPath);
2652:               tree.setLeadSelectionPath(newPath);
2653:             }
2654:         }
2655:       else if (e.getActionCommand().equals("selectNextChangeLead"))
2656:         {
2657:           Object next = getNextVisibleNode(last);
2658:           if (next != null)
2659:             {
2660:               TreePath newPath = new TreePath(getPathToRoot(next, 0));
2661:               selectPath(tree, newPath);
2662:               tree.setLeadSelectionPath(newPath);
2663:             }
2664:         }
2665:     }
2666: 
2667:     /**
2668:      * Returns true if the action is enabled.
2669:      * 
2670:      * @return true if the action is enabled.
2671:      */
2672:     public boolean isEnabled()
2673:     {
2674:       return false;
2675:     }
2676:   }// TreeIncrementAction
2677: 
2678:   /**
2679:    * Forwards all TreeModel events to the TreeState.
2680:    */
2681:   public class TreeModelHandler
2682:     implements TreeModelListener
2683:   {
2684:     /**
2685:      * Constructor
2686:      */
2687:     public TreeModelHandler()
2688:     {
2689:     }
2690: 
2691:     /**
2692:      * Invoked after a node (or a set of siblings) has changed in some way. The
2693:      * node(s) have not changed locations in the tree or altered their children
2694:      * arrays, but other attributes have changed and may affect presentation.
2695:      * Example: the name of a file has changed, but it is in the same location
2696:      * in the file system. To indicate the root has changed, childIndices and
2697:      * children will be null. Use e.getPath() to get the parent of the changed
2698:      * node(s). e.getChildIndices() returns the index(es) of the changed
2699:      * node(s).
2700:      * 
2701:      * @param e
2702:      *          is the event that occured
2703:      */
2704:     public void treeNodesChanged(TreeModelEvent e)
2705:     {
2706:       tree.repaint();
2707:     }
2708: 
2709:     /**
2710:      * Invoked after nodes have been inserted into the tree. Use e.getPath() to
2711:      * get the parent of the new node(s). e.getChildIndices() returns the
2712:      * index(es) of the new node(s) in ascending order.
2713:      * 
2714:      * @param e
2715:      *          is the event that occured
2716:      */
2717:     public void treeNodesInserted(TreeModelEvent e)
2718:     {
2719:       tree.repaint();
2720:     }
2721: 
2722:     /**
2723:      * Invoked after nodes have been removed from the tree. Note that if a
2724:      * subtree is removed from the tree, this method may only be invoked once
2725:      * for the root of the removed subtree, not once for each individual set of
2726:      * siblings removed. Use e.getPath() to get the former parent of the deleted
2727:      * node(s). e.getChildIndices() returns, in ascending order, the index(es)
2728:      * the node(s) had before being deleted.
2729:      * 
2730:      * @param e
2731:      *          is the event that occured
2732:      */
2733:     public void treeNodesRemoved(TreeModelEvent e)
2734:     {
2735:       tree.repaint();
2736:     }
2737: 
2738:     /**
2739:      * Invoked after the tree has drastically changed structure from a given
2740:      * node down. If the path returned by e.getPath() is of length one and the
2741:      * first element does not identify the current root node the first element
2742:      * should become the new root of the tree. Use e.getPath() to get the path
2743:      * to the node. e.getChildIndices() returns null.
2744:      * 
2745:      * @param e
2746:      *          is the event that occured
2747:      */
2748:     public void treeStructureChanged(TreeModelEvent e)
2749:     {
2750:       tree.repaint();
2751:     }
2752:   }// TreeModelHandler
2753: 
2754:   /**
2755:    * TreePageAction handles page up and page down events.
2756:    */
2757:   public class TreePageAction
2758:     extends AbstractAction
2759:   {
2760:     /** Specifies the direction to adjust the selection by. */
2761:     protected int direction;
2762: 
2763:     /**
2764:      * Constructor
2765:      * 
2766:      * @param direction
2767:      *          up or down
2768:      * @param name
2769:      *          is the name of the direction
2770:      */
2771:     public TreePageAction(int direction, String name)
2772:     {
2773:     }
2774: 
2775:     /**
2776:      * Invoked when an action occurs.
2777:      * 
2778:      * @param e
2779:      *          is the event that occured
2780:      */
2781:     public void actionPerformed(ActionEvent e)
2782:     {
2783:     }
2784: 
2785:     /**
2786:      * Returns true if the action is enabled.
2787:      * 
2788:      * @return true if the action is enabled.
2789:      */
2790:     public boolean isEnabled()
2791:     {
2792:       return false;
2793:     }
2794:   }// TreePageAction
2795: 
2796:   /**
2797:    * Listens for changes in the selection model and updates the display
2798:    * accordingly.
2799:    */
2800:   public class TreeSelectionHandler
2801:     implements TreeSelectionListener
2802:   {
2803:     /**
2804:      * Constructor
2805:      */
2806:     public TreeSelectionHandler()
2807:     {
2808:     }
2809: 
2810:     /**
2811:      * Messaged when the selection changes in the tree we're displaying for.
2812:      * Stops editing, messages super and displays the changed paths.
2813:      * 
2814:      * @param event
2815:      *          the event that characterizes the change.
2816:      */
2817:     public void valueChanged(TreeSelectionEvent event)
2818:     {
2819:       if (tree.isEditing())
2820:         tree.cancelEditing();
2821:     }
2822:   }// TreeSelectionHandler
2823: 
2824:   /**
2825:    * For the first selected row expandedness will be toggled.
2826:    */
2827:   public class TreeToggleAction
2828:     extends AbstractAction
2829:   {
2830:     /**
2831:      * Constructor
2832:      * 
2833:      * @param name
2834:      *          is the name of <code>Action</code> field
2835:      */
2836:     public TreeToggleAction(String name)
2837:     {
2838:     }
2839: 
2840:     /**
2841:      * Invoked when an action occurs.
2842:      * 
2843:      * @param e
2844:      *          the event that occured
2845:      */
2846:     public void actionPerformed(ActionEvent e)
2847:     {
2848:     }
2849: 
2850:     /**
2851:      * Returns true if the action is enabled.
2852:      * 
2853:      * @return true if the action is enabled, false otherwise
2854:      */
2855:     public boolean isEnabled()
2856:     {
2857:       return false;
2858:     }
2859:   } // TreeToggleAction
2860: 
2861:   /**
2862:    * TreeTraverseAction is the action used for left/right keys. Will toggle the
2863:    * expandedness of a node, as well as potentially incrementing the selection.
2864:    */
2865:   public class TreeTraverseAction
2866:     extends AbstractAction
2867:   {
2868:     /**
2869:      * Determines direction to traverse, 1 means expand, -1 means collapse.
2870:      */
2871:     protected int direction;
2872: 
2873:     /**
2874:      * Constructor
2875:      * 
2876:      * @param direction
2877:      *          to traverse
2878:      * @param name
2879:      *          is the name of the direction
2880:      */
2881:     public TreeTraverseAction(int direction, String name)
2882:     {
2883:     }
2884: 
2885:     /**
2886:      * Invoked when an action occurs.
2887:      * 
2888:      * @param e
2889:      *          the event that occured
2890:      */
2891:     public void actionPerformed(ActionEvent e)
2892:     {
2893:       TreeModel mod = tree.getModel();
2894:       Object last = tree.getLeadSelectionPath().getLastPathComponent();
2895: 
2896:       if (e.getActionCommand().equals("selectParent"))
2897:         {
2898:           TreePath path = new TreePath(getPathToRoot(last, 0));
2899:           Object p = getParent(mod.getRoot(), last);
2900: 
2901:           if (!mod.isLeaf(last) && tree.isExpanded(path))
2902:             tree.collapsePath(path);
2903:           else if (p != null)
2904:             selectPath(tree, new TreePath(getPathToRoot(p, 0)));
2905:         }
2906:       else if (e.getActionCommand().equals("selectChild"))
2907:         {
2908:           TreePath path = new TreePath(getPathToRoot(last, 0));
2909: 
2910:           if (!mod.isLeaf(last) && tree.isCollapsed(path))
2911:             tree.expandPath(path);
2912:           else
2913:             {
2914:               Object next = getNextVisibleNode(last);
2915: 
2916:               if (next != null)
2917:                 selectPath(tree, new TreePath(getPathToRoot(next, 0)));
2918:             }
2919:         }
2920:     }
2921: 
2922:     /**
2923:      * Returns true if the action is enabled.
2924:      * 
2925:      * @return true if the action is enabled, false otherwise
2926:      */
2927:     public boolean isEnabled()
2928:     {
2929:       return false;
2930:     }
2931:   } // TreeTraverseAction
2932: 
2933:   /**
2934:    * Returns the cell bounds for painting selected cells Package private for use
2935:    * in inner classes.
2936:    * 
2937:    * @param x
2938:    *          is the x location of the cell
2939:    * @param y
2940:    *          is the y location of the cell
2941:    * @param cell
2942:    *          is the Object to get the bounds for
2943:    * @returns Rectangle that represents the cell bounds
2944:    */
2945:   Rectangle getCellBounds(int x, int y, Object cell)
2946:   {
2947:     if (cell != null)
2948:       {
2949:         String s = cell.toString();
2950:         Font f = tree.getFont();
2951:         FontMetrics fm = tree.getToolkit().getFontMetrics(f);
2952: 
2953:         if (s != null)
2954:           return new Rectangle(x, y,
2955:                                SwingUtilities.computeStringWidth(fm, s) + 4,
2956:                                fm.getHeight());
2957:       }
2958:     return new Rectangle(x, y, 0, 0);
2959:   }
2960: 
2961:   /**
2962:    * Retrieves the location of some node, recursively starting at from some
2963:    * node. Package private for use in inner classes.
2964:    * 
2965:    * @param x
2966:    *          is the starting x position, offset
2967:    * @param y
2968:    *          is the starting y position, offset
2969:    * @param tree
2970:    *          is the tree to traverse
2971:    * @param mod
2972:    *          is the TreeModel to use
2973:    * @param node
2974:    *          is the node to get the location for
2975:    * @param startNode
2976:    *          is the node to start searching from
2977:    * @return Point - the location of node
2978:    */
2979:   Point getCellLocation(int x, int y, JTree tree, TreeModel mod, Object node,
2980:                         Object startNode)
2981:   {
2982:     int rowHeight = getRowHeight();
2983:     if (startNode == null || startNode.equals(node))
2984:       {
2985:         if (!tree.isRootVisible()
2986:             && tree.isExpanded(new TreePath(mod.getRoot())))
2987:           return new Point(x + ((getLevel(node)) * rightChildIndent), y);
2988: 
2989:         return new Point(x + ((getLevel(node) + 1) * rightChildIndent), y);
2990:       }
2991: 
2992:     if (!mod.isLeaf(startNode)
2993:         && tree.isExpanded(new TreePath(getPathToRoot(startNode, 0)))
2994:         && !mod.isLeaf(startNode) && mod.getChildCount(startNode) > 0)
2995:       {
2996:         Object child = mod.getChild(startNode, 0);
2997:         if (child != null)
2998:           return getCellLocation(x, y + rowHeight, tree, mod, node, child);
2999:       }
3000: 
3001:     return getCellLocation(x, y + rowHeight, tree, mod, node,
3002:                            getNextVisibleNode(startNode));
3003:   }
3004: 
3005:   /**
3006:    * Paints a node in the tree Package private for use in inner classes.
3007:    * 
3008:    * @param g
3009:    *          the Graphics context in which to paint
3010:    * @param x
3011:    *          the x location of the node
3012:    * @param y
3013:    *          the y location of the node
3014:    * @param tree
3015:    *          the tree to draw on
3016:    * @param node
3017:    *          the object to draw
3018:    */
3019:   void paintNode(Graphics g, int x, int y, JTree tree, Object node,
3020:                  boolean isLeaf)
3021:   {
3022:     TreePath curr = new TreePath(getPathToRoot(node, 0));
3023:     boolean selected = tree.isPathSelected(curr);
3024:     boolean expanded = false;
3025:     boolean hasIcons = false;
3026: 
3027:     if (tree.isVisible(curr))
3028:       {
3029:         if (!isLeaf)
3030:           expanded = tree.isExpanded(curr);
3031: 
3032:         if (editingComponent != null && editingPath != null && isEditing(tree)
3033:             && node.equals(editingPath.getLastPathComponent()))
3034:           {
3035:             Rectangle bounds = getPathBounds(tree, editingPath);
3036:             rendererPane.paintComponent(g, editingComponent.getParent(), null,
3037:                                         new Rectangle(0, 0, bounds.width,
3038:                                                       bounds.height));
3039:           }
3040:         else
3041:           {
3042:             TreeCellRenderer dtcr = tree.getCellRenderer();
3043:             if (dtcr == null)
3044:               dtcr = createDefaultCellRenderer();
3045: 
3046:             int row = getRowForPath(tree, curr);
3047: 
3048:             Component c = dtcr.getTreeCellRendererComponent(tree, node,
3049:                                                             selected, expanded,
3050:                                                             isLeaf, row, false);
3051: 
3052:             rendererPane.paintComponent(g, c, c.getParent(),
3053:                                         getCellBounds(x, y, node));
3054:           }
3055:       }
3056:   }
3057: 
3058:   /**
3059:    * Recursively paints all elements of the tree Package private for use in
3060:    * inner classes.
3061:    * 
3062:    * @param g
3063:    *          the Graphics context in which to paint
3064:    * @param indentation
3065:    *          of the current object
3066:    * @param descent
3067:    *          is the number of elements drawn
3068:    * @param childNumber
3069:    *          is the index of the current child in the tree
3070:    * @param depth
3071:    *          is the depth of the current object in the tree
3072:    * @param tree
3073:    *          is the tree to draw to
3074:    * @param mod
3075:    *          is the TreeModel we are using to draw
3076:    * @param curr
3077:    *          is the current object to draw
3078:    * @return int - current descent of the tree
3079:    */
3080:   int paintRecursive(Graphics g, int indentation, int descent, int childNumber,
3081:                      int depth, JTree tree, TreeModel mod, Object curr)
3082:   {
3083:     Rectangle clip = g.getClipBounds();
3084:     if (indentation > clip.x + clip.width + rightChildIndent
3085:         || descent > clip.y + clip.height + getRowHeight())
3086:       return descent;
3087: 
3088:     int halfHeight = getRowHeight() / 2;
3089:     int halfWidth = rightChildIndent / 2;
3090:     int y0 = descent + halfHeight;
3091:     int heightOfLine = descent + halfHeight;
3092:     boolean isRootVisible = tree.isRootVisible();
3093: 
3094:     if (mod.isLeaf(curr))
3095:       {
3096:         paintNode(g, indentation + 4, descent, tree, curr, true);
3097:         descent += getRowHeight();
3098:       }
3099:     else
3100:       {
3101:         if (depth > 0 || isRootVisible)
3102:           {
3103:             paintNode(g, indentation + 4, descent, tree, curr, false);
3104:             descent += getRowHeight();
3105:             y0 += halfHeight;
3106:           }
3107: 
3108:         int max = 0;
3109:         if (!mod.isLeaf(curr))
3110:           max = mod.getChildCount(curr);
3111:         if (tree.isExpanded(new TreePath(getPathToRoot(curr, 0))))
3112:           {
3113:             for (int i = 0; i < max; i++)
3114:               {
3115:                 int indent = indentation + rightChildIndent;
3116:                 if (!isRootVisible && depth == 0)
3117:                   indent = 0;
3118:                 else if ((!isRootVisible && !curr.equals(mod.getRoot()))
3119:                          || isRootVisible)
3120:                   {
3121:                     g.setColor(getHashColor());
3122:                     heightOfLine = descent + halfHeight;
3123:                     g.drawLine(indentation + halfWidth, heightOfLine,
3124:                                indentation + rightChildIndent, heightOfLine);
3125:                   }
3126: 
3127:                 descent = paintRecursive(g, indent, descent, i, depth + 1,
3128:                                          tree, mod, mod.getChild(curr, i));
3129:               }
3130:           }
3131:       }
3132: 
3133:     if (tree.isExpanded(new TreePath(getPathToRoot(curr, 0))))
3134:       if (y0 != heightOfLine && !mod.isLeaf(curr)
3135:           && mod.getChildCount(curr) > 0)
3136:         {
3137:           g.setColor(getHashColor());
3138:           g.drawLine(indentation + halfWidth, y0, indentation + halfWidth,
3139:                      heightOfLine);
3140:         }
3141: 
3142:     return descent;
3143:   }
3144: 
3145:   /**
3146:    * Recursively paints all the control icons on the tree. Package private for
3147:    * use in inner classes.
3148:    * 
3149:    * @param g
3150:    *          the Graphics context in which to paint
3151:    * @param indentation
3152:    *          of the current object
3153:    * @param descent
3154:    *          is the number of elements drawn
3155:    * @param childNumber
3156:    *          is the index of the current child in the tree
3157:    * @param depth
3158:    *          is the depth of the current object in the tree
3159:    * @param tree
3160:    *          is the tree to draw to
3161:    * @param mod
3162:    *          is the TreeModel we are using to draw
3163:    * @param curr
3164:    *          is the current object to draw
3165:    * @return int - current descent of the tree
3166:    */
3167:   int paintControlIcons(Graphics g, int indentation, int descent,
3168:                         int childNumber, int depth, JTree tree, TreeModel mod,
3169:                         Object node)
3170:   {
3171:     int h = descent;
3172:     int rowHeight = getRowHeight();
3173:     Icon ei = UIManager.getLookAndFeelDefaults().getIcon("Tree.expandedIcon");
3174:     Icon ci = UIManager.getLookAndFeelDefaults().getIcon("Tree.collapsedIcon");
3175:     Rectangle clip = g.getClipBounds();
3176:     if (indentation > clip.x + clip.width + rightChildIndent
3177:         || descent > clip.y + clip.height + getRowHeight())
3178:       return descent;
3179: 
3180:     if (mod.isLeaf(node))
3181:       descent += rowHeight;
3182:     else
3183:       {
3184:         if (depth > 0 || tree.isRootVisible())
3185:           descent += rowHeight;
3186: 
3187:         int max = 0;
3188:         if (!mod.isLeaf(node))
3189:           max = mod.getChildCount(node);
3190:         if (tree.isExpanded(new TreePath(getPathToRoot(node, 0))))
3191:           {
3192:             if (!node.equals(mod.getRoot()))
3193:               ei.paintIcon(tree, g, indentation - rightChildIndent - 3, h);
3194: 
3195:             for (int i = 0; i < max; i++)
3196:               {
3197:                 int indent = indentation + rightChildIndent;
3198:                 if (depth == 0 && !tree.isRootVisible())
3199:                   indent = -1;
3200: 
3201:                 descent = paintControlIcons(g, indent, descent, i, depth + 1,
3202:                                             tree, mod, mod.getChild(node, i));
3203:               }
3204:           }
3205:         else if (!node.equals(mod.getRoot()))
3206:           ci.paintIcon(tree, g, indentation - rightChildIndent - 3,
3207:                        descent - getRowHeight());
3208:       }
3209: 
3210:     return descent;
3211:   }
3212: 
3213:   /**
3214:    * Returns true if the LookAndFeel implements the control icons Package
3215:    * private for use in inner classes.
3216:    * 
3217:    * @return true if control icons are visible
3218:    */
3219:   boolean hasControlIcons()
3220:   {
3221:     if (UIManager.getLookAndFeelDefaults().getIcon("Tree.expandedIcon") == null
3222:         || UIManager.getLookAndFeelDefaults().getIcon("Tree.collapsedIcon") == null)
3223:       return false;
3224:     return true;
3225:   }
3226: 
3227:   /**
3228:    * Returns the parent of the current node
3229:    * 
3230:    * @param root
3231:    *          is the root of the tree
3232:    * @param node
3233:    *          is the current node
3234:    * @return is the parent of the current node
3235:    */
3236:   Object getParent(Object root, Object node)
3237:   {
3238:     if (root == null || node == null)
3239:       return null;
3240:     if (node instanceof TreeNode)
3241:       return ((TreeNode) node).getParent();
3242:     return findNode(root, node);
3243:   }
3244: 
3245:   /**
3246:    * Recursively checks the tree for the specified node, starting at the root.
3247:    * 
3248:    * @param root
3249:    *          is starting node to start searching at.
3250:    * @param node
3251:    *          is the node to search for
3252:    * @return the parent node of node
3253:    */
3254:   private Object findNode(Object root, Object node)
3255:   {
3256:     TreeModel mod = tree.getModel();
3257:     int size = 0;
3258:     if (!mod.isLeaf(root))
3259:       size = mod.getChildCount(root);
3260:     for (int i = 0; i < size; i++)
3261:       {
3262:         if (mod.getIndexOfChild(root, node) != -1)
3263:           return root;
3264: 
3265:         Object n = findNode(mod.getChild(root, i), node);
3266:         if (n != null)
3267:           return n;
3268:       }
3269:     return null;
3270:   }
3271: 
3272:   /**
3273:    * Get next visible node in the tree. Package private for use in inner
3274:    * classes.
3275:    * 
3276:    * @param the
3277:    *          current node
3278:    * @return the next visible node in the JTree. Return null if there are no
3279:    *         more.
3280:    */
3281:   Object getNextVisibleNode(Object node)
3282:   {
3283:     Object next = null;
3284:     TreePath current = null;
3285: 
3286:     if (node != null)
3287:       next = getNextNode(node);
3288: 
3289:     if (next != null)
3290:       {
3291:         current = new TreePath(getPathToRoot(next, 0));
3292:         if (tree.isVisible(current))
3293:           return next;
3294: 
3295:         while (next != null && !tree.isVisible(current))
3296:           {
3297:             next = getNextNode(next);
3298: 
3299:             if (next != null)
3300:               current = new TreePath(getPathToRoot(next, 0));
3301:           }
3302:       }
3303:     return next;
3304:   }
3305: 
3306:   /**
3307:    * Get previous visible node in the tree. Package private for use in inner
3308:    * classes.
3309:    * 
3310:    * @param the
3311:    *          current node
3312:    * @return the next visible node in the JTree. Return null if there are no
3313:    *         more.
3314:    */
3315:   Object getPreviousVisibleNode(Object node)
3316:   {
3317:     Object prev = null;
3318:     TreePath current = null;
3319: 
3320:     if (node != null)
3321:       prev = getPreviousNode(node);
3322: 
3323:     if (prev != null)
3324:       {
3325:         current = new TreePath(getPathToRoot(prev, 0));
3326:         if (tree.isVisible(current))
3327:           return prev;
3328: 
3329:         while (prev != null && !tree.isVisible(current))
3330:           {
3331:             prev = getPreviousNode(prev);
3332: 
3333:             if (prev != null)
3334:               current = new TreePath(getPathToRoot(prev, 0));
3335:           }
3336:       }
3337:     return prev;
3338:   }
3339: 
3340:   /**
3341:    * Returns the next node in the tree Package private for use in inner classes.
3342:    * 
3343:    * @param the
3344:    *          current node
3345:    * @return the next node in the tree
3346:    */
3347:   Object getNextNode(Object curr)
3348:   {
3349:     TreeModel mod = tree.getModel();
3350:     if (!mod.isLeaf(curr) && mod.getChildCount(curr) > 0)
3351:       return mod.getChild(curr, 0);
3352: 
3353:     Object node = curr;
3354:     Object sibling = null;
3355: 
3356:     do
3357:       {
3358:         sibling = getNextSibling(node);
3359:         node = getParent(mod.getRoot(), node);
3360:       }
3361:     while (sibling == null && node != null);
3362: 
3363:     return sibling;
3364:   }
3365: 
3366:   /**
3367:    * Returns the previous node in the tree Package private for use in inner
3368:    * classes.
3369:    * 
3370:    * @param the
3371:    *          current node
3372:    * @return the previous node in the tree
3373:    */
3374:   Object getPreviousNode(Object node)
3375:   {
3376:     TreeModel mod = tree.getModel();
3377:     Object parent = getParent(mod.getRoot(), node);
3378:     if (parent == null)
3379:       return null;
3380: 
3381:     Object sibling = getPreviousSibling(node);
3382: 
3383:     if (sibling == null)
3384:       return parent;
3385: 
3386:     int size = 0;
3387:     if (!mod.isLeaf(sibling))
3388:       size = mod.getChildCount(sibling);
3389:     while (size > 0)
3390:       {
3391:         sibling = mod.getChild(sibling, size - 1);
3392:         if (!mod.isLeaf(sibling))
3393:           size = mod.getChildCount(sibling);
3394:         else
3395:           size = 0;
3396:       }
3397: 
3398:     return sibling;
3399:   }
3400: 
3401:   /**
3402:    * Returns the next sibling in the tree Package private for use in inner
3403:    * classes.
3404:    * 
3405:    * @param the
3406:    *          current node
3407:    * @return the next sibling in the tree
3408:    */
3409:   Object getNextSibling(Object node)
3410:   {
3411:     TreeModel mod = tree.getModel();
3412:     Object parent = getParent(mod.getRoot(), node);
3413:     if (parent == null)
3414:       return null;
3415: 
3416:     int index = mod.getIndexOfChild(parent, node) + 1;
3417: 
3418:     int size = 0;
3419:     if (!mod.isLeaf(parent))
3420:       size = mod.getChildCount(parent);
3421:     if (index == 0 || index >= size)
3422:       return null;
3423: 
3424:     return mod.getChild(parent, index);
3425:   }
3426: 
3427:   /**
3428:    * Returns the previous sibling in the tree Package private for use in inner
3429:    * classes.
3430:    * 
3431:    * @param the
3432:    *          current node
3433:    * @return the previous sibling in the tree
3434:    */
3435:   Object getPreviousSibling(Object node)
3436:   {
3437:     TreeModel mod = tree.getModel();
3438:     Object parent = getParent(mod.getRoot(), node);
3439:     if (parent == null)
3440:       return null;
3441: 
3442:     int index = mod.getIndexOfChild(parent, node) - 1;
3443: 
3444:     int size = 0;
3445:     if (!mod.isLeaf(parent))
3446:       size = mod.getChildCount(parent);
3447:     if (index < 0 || index >= size)
3448:       return null;
3449: 
3450:     return mod.getChild(parent, index);
3451:   }
3452: 
3453:   /**
3454:    * Selects the specified path in the tree depending on modes. Package private
3455:    * for use in inner classes.
3456:    * 
3457:    * @param tree
3458:    *          is the tree we are selecting the path in
3459:    * @param path
3460:    *          is the path we are selecting
3461:    */
3462:   void selectPath(JTree tree, TreePath path)
3463:   {
3464:     if (path != null)
3465:       {
3466:         if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
3467:           {
3468:             tree.addSelectionPath(path);
3469:             tree.setLeadSelectionPath(path);
3470:           }
3471:         else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
3472:           {
3473:             // TODO
3474:           }
3475:         else
3476:           {
3477:             tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
3478: 
3479:             tree.getSelectionModel().clearSelection();
3480:             tree.addSelectionPath(path);
3481:             tree.setLeadSelectionPath(path);
3482:           }
3483:       }
3484:   }
3485: 
3486:   /**
3487:    * Returns the path from node to the root. Package private for use in inner
3488:    * classes.
3489:    * 
3490:    * @param node
3491:    *          the node to get the path to
3492:    * @param depth
3493:    *          the depth of the tree to return a path for
3494:    * @return an array of tree nodes that represent the path to node.
3495:    */
3496:   Object[] getPathToRoot(Object node, int depth)
3497:   {
3498:     TreeModel mod = tree.getModel();
3499:     if (node == null)
3500:       {
3501:         if (depth == 0)
3502:           return null;
3503: 
3504:         return new Object[depth];
3505:       }
3506: 
3507:     Object[] path = getPathToRoot(getParent(mod.getRoot(), node), depth + 1);
3508:     path[path.length - depth - 1] = node;
3509:     return path;
3510:   }
3511: 
3512:   /**
3513:    * Returns the level of the node in the tree.
3514:    * 
3515:    * @param the
3516:    *          current node
3517:    * @return the number of the level
3518:    */
3519:   int getLevel(Object node)
3520:   {
3521:     int count = -1;
3522:     Object current = node;
3523: 
3524:     do
3525:       {
3526:         current = getParent(tree.getModel().getRoot(), current);
3527:         count++;
3528:       }
3529:     while (current != null);
3530: 
3531:     return count;
3532:   }
3533: 
3534:   /**
3535:    * Draws a vertical line using the given graphic context
3536:    * 
3537:    * @param g
3538:    *          is the graphic context
3539:    * @param c
3540:    *          is the component the new line will belong to
3541:    * @param x
3542:    *          is the horizonal position
3543:    * @param top
3544:    *          specifies the top of the line
3545:    * @param bottom
3546:    *          specifies the bottom of the line
3547:    */
3548:   protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
3549:                                    int bottom)
3550:   {
3551:     g.drawLine(x, top, x, bottom);
3552:   }
3553: 
3554:   /**
3555:    * Draws a horizontal line using the given graphic context
3556:    * 
3557:    * @param g
3558:    *          is the graphic context
3559:    * @param c
3560:    *          is the component the new line will belong to
3561:    * @param y
3562:    *          is the vertical position
3563:    * @param left
3564:    *          specifies the left point of the line
3565:    * @param right
3566:    *          specifies the right point of the line
3567:    */
3568:   protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
3569:                                      int right)
3570:   {
3571:     g.drawLine(left, y, right, y);
3572:   }
3573: 
3574:   /**
3575:    * Draws an icon at around a specific position
3576:    * 
3577:    * @param c
3578:    *          is the component the new line will belong to
3579:    * @param g
3580:    *          is the graphic context
3581:    * @param icon
3582:    *          is the icon which will be drawn
3583:    * @param x
3584:    *          is the center position in x-direction
3585:    * @param y
3586:    *          is the center position in y-direction FIXME what to do if x <
3587:    *          (icon.width / 2). Same with y
3588:    */
3589:   protected void drawCentered(JComponent c, Graphics g, Icon icon, int x, int y)
3590:   {
3591:     int beginPositionX = x - icon.getIconWidth() / 2;
3592:     int beginPositionY = y - icon.getIconHeight() / 2;
3593:     icon.paintIcon(c, g, beginPositionX, beginPositionY);
3594:   }
3595: } // BasicTreeUI