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: 
  64: import java.beans.PropertyChangeEvent;
  65: import java.beans.PropertyChangeListener;
  66: 
  67: import javax.swing.AbstractAction;
  68: import javax.swing.Action;
  69: import javax.swing.CellRendererPane;
  70: import javax.swing.Icon;
  71: import javax.swing.JComponent;
  72: import javax.swing.JScrollBar;
  73: import javax.swing.JScrollPane;
  74: import javax.swing.JTree;
  75: import javax.swing.SwingUtilities;
  76: import javax.swing.Timer;
  77: import javax.swing.UIDefaults;
  78: import javax.swing.UIManager;
  79: import javax.swing.event.CellEditorListener;
  80: import javax.swing.event.ChangeEvent;
  81: import javax.swing.event.MouseInputListener;
  82: import javax.swing.event.TreeExpansionEvent;
  83: import javax.swing.event.TreeExpansionListener;
  84: import javax.swing.event.TreeModelEvent;
  85: import javax.swing.event.TreeModelListener;
  86: import javax.swing.event.TreeSelectionEvent;
  87: import javax.swing.event.TreeSelectionListener;
  88: import javax.swing.plaf.ComponentUI;
  89: import javax.swing.plaf.TreeUI;
  90: import javax.swing.tree.AbstractLayoutCache;
  91: import javax.swing.tree.FixedHeightLayoutCache;
  92: import javax.swing.tree.DefaultMutableTreeNode;
  93: import javax.swing.tree.DefaultTreeCellEditor;
  94: import javax.swing.tree.DefaultTreeCellRenderer;
  95: import javax.swing.tree.TreeCellEditor;
  96: import javax.swing.tree.TreeCellRenderer;
  97: import javax.swing.tree.TreeSelectionModel;
  98: import javax.swing.tree.TreeModel;
  99: import javax.swing.tree.TreeNode;
 100: import javax.swing.tree.TreePath;
 101: 
 102: import java.util.Enumeration;
 103: import java.util.Hashtable;
 104: 
 105: /**
 106:  * A delegate providing the user interface for <code>JTree</code> according to
 107:  * the Basic look and feel.
 108:  * 
 109:  * @see javax.swing.JTree
 110:  * @author Sascha Brawer (brawer@dandelis.ch)
 111:  * @author Lillian Angel (langel@redhat.com)
 112:  */
 113: public class BasicTreeUI
 114:       extends TreeUI
 115: {
 116: 
 117:    /** Collapse Icon for the tree. */
 118:    protected transient Icon collapsedIcon;
 119: 
 120:    /** Expanded Icon for the tree. */
 121:    protected transient Icon expandedIcon;
 122: 
 123:    /** Distance between left margin and where vertical dashes will be drawn. */
 124:    protected int leftChildIndent;
 125: 
 126:    /**
 127:     * Distance between leftChildIndent and where cell contents will be drawn.
 128:     */
 129:    protected int rightChildIndent;
 130: 
 131:    /**
 132:     * Total fistance that will be indented. The sum of leftChildIndent and
 133:     * rightChildIndent .
 134:     */
 135:    protected int totalChildIndent;
 136: 
 137:    /** Minimum preferred size. */
 138:    protected Dimension preferredMinsize;
 139: 
 140:    /** Index of the row that was last selected. */
 141:    protected int lastSelectedRow;
 142: 
 143:    /** Component that we're going to be drawing onto. */
 144:    protected JTree tree;
 145: 
 146:    /** Renderer that is being used to do the actual cell drawing. */
 147:    protected transient TreeCellRenderer currentCellRenderer;
 148: 
 149:    /**
 150:     * Set to true if the renderer that is currently in the tree was created by
 151:     * this instance.
 152:     */
 153:    protected boolean createdRenderer;
 154: 
 155:    /** Editor for the tree. */
 156:    protected transient TreeCellEditor cellEditor;
 157: 
 158:    /**
 159:     * Set to true if editor that is currently in the tree was created by this
 160:     * instance.
 161:     */
 162:    protected boolean createdCellEditor;
 163: 
 164:    /**
 165:     * Set to false when editing and shouldSelectCall() returns true meaning the
 166:     * node should be selected before editing, used in completeEditing.
 167:     */
 168:    protected boolean stopEditingInCompleteEditing;
 169: 
 170:    /** Used to paint the TreeCellRenderer. */
 171:    protected CellRendererPane rendererPane;
 172: 
 173:    /** Size needed to completely display all the nodes. */
 174:    protected Dimension preferredSize;
 175: 
 176:    /** Is the preferredSize valid? */
 177:    protected boolean validCachedPreferredSize;
 178: 
 179:    /** Object responsible for handling sizing and expanded issues. */
 180:    protected AbstractLayoutCache treeState;
 181: 
 182:    /** Used for minimizing the drawing of vertical lines. */
 183:    protected Hashtable drawingCache;
 184: 
 185:    /**
 186:     * True if doing optimizations for a largeModel. Subclasses that don't
 187:     * support this may wish to override createLayoutCache to not return a
 188:     * FixedHeightLayoutCache instance.
 189:     */
 190:    protected boolean largeModel;
 191: 
 192:    /** Responsible for telling the TreeState the size needed for a node. */
 193:    protected AbstractLayoutCache.NodeDimensions nodeDimensions;
 194: 
 195:    /** Used to determine what to display. */
 196:    protected TreeModel treeModel;
 197: 
 198:    /** Model maintaining the selection. */
 199:    protected TreeSelectionModel treeSelectionModel;
 200: 
 201:    /**
 202:     * How much the depth should be offset to properly calculate x locations.
 203:     * This is based on whether or not the root is visible, and if the root
 204:     * handles are visible.
 205:     */
 206:    protected int depthOffset;
 207: 
 208:    /**
 209:     * When editing, this will be the Component that is doing the actual editing.
 210:     */
 211:    protected Component editingComponent;
 212: 
 213:    /** Path that is being edited. */
 214:    protected TreePath editingPath;
 215: 
 216:    /**
 217:     * Row that is being edited. Should only be referenced if editingComponent is
 218:     * null.
 219:     */
 220:    protected int editingRow;
 221: 
 222:    /** Set to true if the editor has a different size than the renderer. */
 223:    protected boolean editorHasDifferentSize;
 224: 
 225:    /** Listeners */
 226:    private PropertyChangeListener propertyChangeListener;
 227: 
 228:    private FocusListener focusListener;
 229: 
 230:    private TreeSelectionListener treeSelectionListener;
 231: 
 232:    private MouseInputListener mouseInputListener;
 233: 
 234:    private KeyListener keyListener;
 235: 
 236:    private PropertyChangeListener selectionModelPropertyChangeListener;
 237: 
 238:    private ComponentListener componentListener;
 239: 
 240:    private CellEditorListener cellEditorListener;
 241: 
 242:    private TreeExpansionListener treeExpansionListener;
 243: 
 244:    private TreeModelListener treeModelListener;
 245: 
 246:    /**
 247:     * Creates a new BasicTreeUI object.
 248:     */
 249:    public BasicTreeUI()
 250:    {
 251:       drawingCache = new Hashtable();
 252:       cellEditor = createDefaultCellEditor();
 253:       currentCellRenderer = createDefaultCellRenderer();
 254:       nodeDimensions = createNodeDimensions();
 255:       rendererPane = createCellRendererPane();
 256:       configureLayoutCache();
 257: 
 258:       propertyChangeListener = createPropertyChangeListener();
 259:       focusListener = createFocusListener();
 260:       treeSelectionListener = createTreeSelectionListener();
 261:       mouseInputListener = new MouseInputHandler(null, null, null);
 262:       keyListener = createKeyListener();
 263:       selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener();
 264:       componentListener = createComponentListener();
 265:       cellEditorListener = createCellEditorListener();
 266:       treeExpansionListener = createTreeExpansionListener();
 267:       treeModelListener = createTreeModelListener();
 268: 
 269:       createdRenderer = true;
 270:       createdCellEditor = true;
 271:       editingRow = -1;
 272:       lastSelectedRow = -1;
 273:    }
 274: 
 275:    /**
 276:     * Returns an instance of the UI delegate for the specified component.
 277:     * 
 278:     * @param c the <code>JComponent</code> for which we need a UI delegate
 279:     *        for.
 280:     * @return the <code>ComponentUI</code> for c.
 281:     */
 282:    public static ComponentUI createUI(JComponent c)
 283:    {
 284:       return new BasicTreeUI();
 285:    }
 286: 
 287:    /**
 288:     * Returns the Hash color.
 289:     * 
 290:     * @return the <code>Color</code> of the Hash.
 291:     */
 292:    protected Color getHashColor()
 293:    {
 294:       return UIManager.getLookAndFeelDefaults().getColor("Tree.hash");
 295:    }
 296: 
 297:    /**
 298:     * Sets the Hash color.
 299:     * 
 300:     * @param the <code>Color</code> to set the Hash to.
 301:     */
 302:    protected void setHashColor(Color color)
 303:    {
 304:       // FIXME: not implemented
 305: 
 306:    }
 307: 
 308:    /**
 309:     * Sets the left child's indent value.
 310:     * 
 311:     * @param newAmount is the new indent value for the left child.
 312:     */
 313:    public void setLeftChildIndent(int newAmount)
 314:    {
 315:       leftChildIndent = newAmount;
 316:    }
 317: 
 318:    /**
 319:     * Returns the indent value for the left child.
 320:     * 
 321:     * @return the indent value for the left child.
 322:     */
 323:    public int getLeftChildIndent(int newAmount)
 324:    {
 325:       return leftChildIndent;
 326:    }
 327: 
 328:    /**
 329:     * Sets the right child's indent value.
 330:     * 
 331:     * @param newAmount is the new indent value for the right child.
 332:     */
 333:    public void setRightChildIndent(int newAmount)
 334:    {
 335:       rightChildIndent = newAmount;
 336:    }
 337: 
 338:    /**
 339:     * Returns the indent value for the right child.
 340:     * 
 341:     * @return the indent value for the right child.
 342:     */
 343:    public int getRightChildIndent(int newAmount)
 344:    {
 345:       return rightChildIndent;
 346:    }
 347: 
 348:    /**
 349:     * Sets the expanded icon.
 350:     * 
 351:     * @param newG is the new expanded icon.
 352:     */
 353:    public void setExpandedIcon(Icon newG)
 354:    {
 355:       expandedIcon = newG;
 356:    }
 357: 
 358:    /**
 359:     * Returns the current expanded icon.
 360:     * 
 361:     * @return the current expanded icon.
 362:     */
 363:    public Icon getExpandedIcon()
 364:    {
 365:       return expandedIcon;
 366:    }
 367: 
 368:    /**
 369:     * Sets the collapsed icon.
 370:     * 
 371:     * @param newG is the new collapsed icon.
 372:     */
 373:    public void setCollapsedIcon(Icon newG)
 374:    {
 375:       collapsedIcon = newG;
 376:    }
 377: 
 378:    /**
 379:     * Returns the current collapsed icon.
 380:     * 
 381:     * @return the current collapsed icon.
 382:     */
 383:    public Icon getCollapsedIcon()
 384:    {
 385:       return collapsedIcon;
 386:    }
 387: 
 388:    /**
 389:     * Updates the componentListener, if necessary.
 390:     * 
 391:     * @param largeModel sets this.largeModel to it.
 392:     */
 393:    protected void setLargeModel(boolean largeModel)
 394:    {
 395:       if (largeModel != this.largeModel)
 396:       {
 397:          tree.removeComponentListener(componentListener);
 398:          this.largeModel = largeModel;
 399:          tree.addComponentListener(componentListener);
 400:       }
 401:    }
 402: 
 403:    /**
 404:     * Returns true if largeModel is set
 405:     * 
 406:     * @return true if largeModel is set, otherwise false.
 407:     */
 408:    protected boolean isLargeModel()
 409:    {
 410:       return largeModel;
 411:    }
 412: 
 413:    /**
 414:     * Sets the row height.
 415:     * 
 416:     * @param rowHeight is the height to set this.rowHeight to.
 417:     */
 418:    protected void setRowHeight(int rowHeight)
 419:    {
 420:       treeState.setRowHeight(rowHeight);
 421:    }
 422: 
 423:    /**
 424:     * Returns the current row height.
 425:     * 
 426:     * @return current row height.
 427:     */
 428:    protected int getRowHeight()
 429:    {
 430:       return treeState.getRowHeight();
 431:    }
 432: 
 433:    /**
 434:     * Sets the TreeCellRenderer to <code>tcr</code>. This invokes
 435:     * <code>updateRenderer</code>.
 436:     * 
 437:     * @param tcr is the new TreeCellRenderer.
 438:     */
 439:    protected void setCellRenderer(TreeCellRenderer tcr)
 440:    {
 441:       currentCellRenderer = tcr;
 442:       updateRenderer();
 443:    }
 444: 
 445:    /**
 446:     * Return currentCellRenderer, which will either be the trees renderer, or
 447:     * defaultCellRenderer, which ever was not null.
 448:     * 
 449:     * @return the current Cell Renderer
 450:     */
 451:    protected TreeCellRenderer getCellRenderer()
 452:    {
 453:       if (currentCellRenderer != null)
 454:          return currentCellRenderer;
 455: 
 456:       return createDefaultCellRenderer();
 457:    }
 458: 
 459:    /**
 460:     * Sets the tree's model.
 461:     * 
 462:     * @param model to set the treeModel to.
 463:     */
 464:    protected void setModel(TreeModel model)
 465:    {
 466:       treeState.setModel(model);
 467:       treeModel = model;
 468:    }
 469: 
 470:    /**
 471:     * Returns the tree's model
 472:     * 
 473:     * @return treeModel
 474:     */
 475:    protected TreeModel getModel()
 476:    {
 477:       return treeModel;
 478:    }
 479: 
 480:    /**
 481:     * Sets the root to being visible.
 482:     * 
 483:     * @param newValue sets the visibility of the root
 484:     */
 485:    protected void setRootVisible(boolean newValue)
 486:    {
 487:       treeState.setRootVisible(newValue);
 488:    }
 489: 
 490:    /**
 491:     * Returns true if the root is visible.
 492:     * 
 493:     * @return true if the root is visible.
 494:     */
 495:    protected boolean isRootVisible()
 496:    {
 497:       return treeState.isRootVisible();
 498:    }
 499: 
 500:    /**
 501:     * Determines whether the node handles are to be displayed.
 502:     * 
 503:     * @param newValue sets whether or not node handles should be displayed.
 504:     */
 505:    protected void setShowsRootHandles(boolean newValue)
 506:    {
 507:       tree.setShowsRootHandles(newValue);
 508:    }
 509: 
 510:    /**
 511:     * Returns true if the node handles are to be displayed.
 512:     * 
 513:     * @return true if the node handles are to be displayed.
 514:     */
 515:    protected boolean getShowsRootHandles()
 516:    {
 517:       return tree.getShowsRootHandles();
 518:    }
 519: 
 520:    /**
 521:     * Sets the cell editor.
 522:     * 
 523:     * @param editor to set the cellEditor to.
 524:     */
 525:    protected void setCellEditor(TreeCellEditor editor)
 526:    {
 527:       cellEditor = editor;
 528:    }
 529: 
 530:    /**
 531:     * Returns the <code>TreeCellEditor</code> for this tree.
 532:     * 
 533:     * @return the cellEditor for this tree.
 534:     */
 535:    protected TreeCellEditor getCellEditor()
 536:    {
 537:       return cellEditor;
 538:    }
 539: 
 540:    /**
 541:     * Configures the receiver to allow, or not allow, editing.
 542:     * 
 543:     * @param newValue sets the receiver to allow editing if true.
 544:     */
 545:    protected void setEditable(boolean newValue)
 546:    {
 547:       tree.setEditable(newValue);
 548:    }
 549: 
 550:    /**
 551:     * Returns true if the receiver allows editing.
 552:     * 
 553:     * @return true if the receiver allows editing.
 554:     */
 555:    protected boolean isEditable()
 556:    {
 557:       return tree.isEditable();
 558:    }
 559: 
 560:    /**
 561:     * Resets the selection model. The appropriate listeners are installed on the
 562:     * model.
 563:     * 
 564:     * @param newLSM resets the selection model.
 565:     */
 566:    protected void setSelectionModel(TreeSelectionModel newLSM)
 567:    {
 568:       if (newLSM != null)
 569:       {
 570:          treeSelectionModel = newLSM;
 571:          tree.setSelectionModel(treeSelectionModel);
 572:       }
 573:    }
 574: 
 575:    /**
 576:     * Returns the current selection model.
 577:     * 
 578:     * @return the current selection model.
 579:     */
 580:    protected TreeSelectionModel getSelectionModel()
 581:    {
 582:       return treeSelectionModel;
 583:    }
 584: 
 585:    /**
 586:     * Returns the Rectangle enclosing the label portion that the last item in
 587:     * path will be drawn to. Will return null if any component in path is
 588:     * currently valid.
 589:     * 
 590:     * @param tree is the current tree the path will be drawn to.
 591:     * @param path is the current path the tree to draw to.
 592:     * @return the Rectangle enclosing the label portion that the last item in
 593:     *         the path will be drawn to.
 594:     */
 595:    public Rectangle getPathBounds(JTree tree, TreePath path)
 596:    {
 597:       // FIXME: not implemented
 598:       return null;
 599:    }
 600: 
 601:    /**
 602:     * Returns the path for passed in row. If row is not visible null is
 603:     * returned.
 604:     * 
 605:     * @param tree is the current tree to return path for.
 606:     * @param row is the row number of the row to return.
 607:     * @return the path for passed in row. If row is not visible null is
 608:     *         returned.
 609:     */
 610:    public TreePath getPathForRow(JTree tree, int row)
 611:    {
 612:       DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel())
 613:             .getRoot());
 614: 
 615:       for (int i = 0; i < row; i++)
 616:          node = getNextVisibleNode(node);
 617: 
 618:       // in case nothing was found
 619:       if (node == null)
 620:          return null;
 621: 
 622:       // something was found
 623:       return new TreePath(node.getPath());
 624:    }
 625: 
 626:    /**
 627:     * Get next visible node in the tree.
 628:     * Package private for use in inner classes.
 629:     * @param the current node
 630:     * @return the next visible node in the JTree. Return null if there are no
 631:     *         more.
 632:     */
 633:    DefaultMutableTreeNode getNextVisibleNode(DefaultMutableTreeNode node)
 634:    {
 635:       DefaultMutableTreeNode next = null;
 636:       TreePath current = null;
 637: 
 638:       if (node != null)
 639:          next = node.getNextNode();
 640: 
 641:       if (next != null)
 642:       {
 643:          current = new TreePath(next.getPath());
 644:          if (tree.isVisible(current))
 645:             return next;
 646: 
 647:          while (next != null && !tree.isVisible(current))
 648:          {
 649:             next = next.getNextNode();
 650: 
 651:             if (next != null)
 652:                current = new TreePath(next.getPath());
 653:          }
 654:       }
 655:       return next;
 656:    }
 657: 
 658:    /**
 659:     * Get previous visible node in the tree.
 660:     * Package private for use in inner classes.
 661:     * 
 662:     * @param the current node
 663:     * @return the next visible node in the JTree. Return null if there are no
 664:     *         more.
 665:     */
 666:    DefaultMutableTreeNode getPreviousVisibleNode
 667:                                              (DefaultMutableTreeNode node)
 668:    {
 669:       DefaultMutableTreeNode prev = null;
 670:       TreePath current = null;
 671: 
 672:       if (node != null)
 673:          prev = node.getPreviousNode();
 674: 
 675:       if (prev != null)
 676:       {
 677:          current = new TreePath(prev.getPath());
 678:          if (tree.isVisible(current))
 679:             return prev;
 680: 
 681:          while (prev != null && !tree.isVisible(current))
 682:          {
 683:             prev = prev.getPreviousNode();
 684: 
 685:             if (prev != null)
 686:                current = new TreePath(prev.getPath());
 687:          }
 688:       }
 689:       return prev;
 690:    }
 691:    
 692:    /**
 693:     * Returns the row that the last item identified in path is visible at. Will
 694:     * return -1 if any of the elments in the path are not currently visible.
 695:     * 
 696:     * @param tree is the current tree to return the row for.
 697:     * @param path is the path used to find the row.
 698:     * @return the row that the last item identified in path is visible at. Will
 699:     *         return -1 if any of the elments in the path are not currently
 700:     *         visible.
 701:     */
 702:    public int getRowForPath(JTree tree, TreePath path)
 703:    {
 704:       // FIXME: check visibility
 705:       // right now, just returns last element because
 706:       // expand/collapse is not implemented
 707:       return path.getPathCount() - 1;
 708:    }
 709: 
 710:    /**
 711:     * Returns the number of rows that are being displayed.
 712:     * 
 713:     * @param tree is the current tree to return the number of rows for.
 714:     * @return the number of rows being displayed.
 715:     */
 716:    public int getRowCount(JTree tree)
 717:    {
 718:       DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel())
 719:             .getRoot());
 720:       int count = 0;
 721:       
 722:       while (node != null)
 723:       {
 724:          count++;
 725:          node = getNextVisibleNode(node);
 726:       }
 727:       
 728:       return count;
 729:    }
 730: 
 731:    /**
 732:     * Returns the path to the node that is closest to x,y. If there is nothing
 733:     * currently visible this will return null, otherwise it'll always return a
 734:     * valid path. If you need to test if the returned object is exactly at x,y
 735:     * you should get the bounds for the returned path and test x,y against that.
 736:     * 
 737:     * @param tree the tree to search for the closest path
 738:     * @param x is the x coordinate of the location to search
 739:     * @param y is the y coordinate of the location to search
 740:     * @return the tree path closes to x,y.
 741:     */
 742:    public TreePath getClosestPathForLocation(JTree tree, int x, int y)
 743:    {
 744:       return treeState.getPathClosestTo(x, y);
 745:    }
 746: 
 747:    /**
 748:     * Returns true if the tree is being edited. The item that is being edited
 749:     * can be returned by getEditingPath().
 750:     * 
 751:     * @param tree is the tree to check for editing.
 752:     * @return true if the tree is being edited.
 753:     */
 754:    public boolean isEditing(JTree tree)
 755:    {
 756:       // FIXME: not implemented
 757:       return false;
 758:    }
 759: 
 760:    /**
 761:     * Stops the current editing session. This has no effect if the tree is not
 762:     * being edited. Returns true if the editor allows the editing session to
 763:     * stop.
 764:     * 
 765:     * @param tree is the tree to stop the editing on
 766:     * @return true if the editor allows the editing session to stop.
 767:     */
 768:    public boolean stopEditing(JTree tree)
 769:    {
 770:       // FIXME: not implemented
 771:       return false;
 772:    }
 773: 
 774:    /**
 775:     * Cancels the current editing session.
 776:     * 
 777:     * @param tree is the tree to cancel the editing session on.
 778:     */
 779:    public void cancelEditing(JTree tree)
 780:    {
 781:       // FIXME: not implemented
 782:    }
 783: 
 784:    /**
 785:     * Selects the last item in path and tries to edit it. Editing will fail if
 786:     * the CellEditor won't allow it for the selected item.
 787:     * 
 788:     * @param tree is the tree to edit on.
 789:     * @param path is the path in tree to edit on.
 790:     */
 791:    public void startEditingAtPath(JTree tree, TreePath path)
 792:    {
 793:       // FIXME: not implemented
 794:    }
 795: 
 796:    /**
 797:     * Returns the path to the element that is being editted.
 798:     * 
 799:     * @param tree is the tree to get the editing path from.
 800:     * @return the path that is being edited.
 801:     */
 802:    public TreePath getEditingPath(JTree tree)
 803:    {
 804:       // FIXME: not implemented
 805:       return null;
 806:    }
 807: 
 808:    /**
 809:     * Invoked after the tree instance variable has been set, but before any
 810:     * default/listeners have been installed.
 811:     */
 812:    protected void prepareForUIInstall()
 813:    {
 814:       // FIXME: not implemented
 815:    }
 816: 
 817:    /**
 818:     * Invoked from installUI after all the defaults/listeners have been
 819:     * installed.
 820:     */
 821:    protected void completeUIInstall()
 822:    {
 823:       // FIXME: not implemented
 824:    }
 825: 
 826:    /**
 827:     * Invoked from uninstallUI after all the defaults/listeners have been
 828:     * uninstalled.
 829:     */
 830:    protected void completeUIUninstall()
 831:    {
 832:       // FIXME: not implemented
 833:    }
 834: 
 835:    /**
 836:     * Installs the subcomponents of the tree, which is the renderer pane.
 837:     */
 838:    protected void installComponents()
 839:    {
 840:       // FIXME: not implemented
 841:    }
 842: 
 843:    /**
 844:     * Creates an instance of NodeDimensions that is able to determine the size
 845:     * of a given node in the tree.
 846:     * 
 847:     * @return the NodeDimensions of a given node in the tree
 848:     */
 849:    protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
 850:    {
 851:       // FIXME: not implemented
 852:       return null;
 853:    }
 854: 
 855:    /**
 856:     * Creates a listener that is reponsible for the updates the UI based on how
 857:     * the tree changes.
 858:     * 
 859:     * @return the PropertyChangeListener that is reposnsible for the updates
 860:     */
 861:    protected PropertyChangeListener createPropertyChangeListener()
 862:    {
 863:       return new PropertyChangeHandler();
 864:    }
 865: 
 866:    /**
 867:     * Creates the listener responsible for updating the selection based on mouse
 868:     * events.
 869:     * 
 870:     * @return the MouseListener responsible for updating.
 871:     */
 872:    protected MouseListener createMouseListener()
 873:    {
 874:       return new MouseHandler();
 875:    }
 876: 
 877:    /**
 878:     * Creates the listener that is responsible for updating the display when
 879:     * focus is lost/grained.
 880:     * 
 881:     * @return the FocusListener responsible for updating.
 882:     */
 883:    protected FocusListener createFocusListener()
 884:    {
 885:       return new FocusHandler();
 886:    }
 887: 
 888:    /**
 889:     * Creates the listener reponsible for getting key events from the tree.
 890:     * 
 891:     * @return the KeyListener responsible for getting key events.
 892:     */
 893:    protected KeyListener createKeyListener()
 894:    {
 895:       return new KeyHandler();
 896:    }
 897: 
 898:    /**
 899:     * Creates the listener responsible for getting property change events from
 900:     * the selection model.
 901:     * 
 902:     * @returns the PropertyChangeListener reponsible for getting property change
 903:     *          events from the selection model.
 904:     */
 905:    protected PropertyChangeListener createSelectionModelPropertyChangeListener()
 906:    {
 907:       return new SelectionModelPropertyChangeHandler();
 908:    }
 909: 
 910:    /**
 911:     * Creates the listener that updates the display based on selection change
 912:     * methods.
 913:     * 
 914:     * @return the TreeSelectionListener responsible for updating.
 915:     */
 916:    protected TreeSelectionListener createTreeSelectionListener()
 917:    {
 918:       return new TreeSelectionHandler();
 919:    }
 920: 
 921:    /**
 922:     * Creates a listener to handle events from the current editor
 923:     * 
 924:     * @return the CellEditorListener that handles events from the current editor
 925:     */
 926:    protected CellEditorListener createCellEditorListener()
 927:    {
 928:       return new CellEditorHandler();
 929:    }
 930: 
 931:    /**
 932:     * Creates and returns a new ComponentHandler. This is used for the large
 933:     * model to mark the validCachedPreferredSize as invalid when the component
 934:     * moves.
 935:     * 
 936:     * @return a new ComponentHandler.
 937:     */
 938:    protected ComponentListener createComponentListener()
 939:    {
 940:       return new ComponentHandler();
 941:    }
 942: 
 943:    /**
 944:     * Creates and returns the object responsible for updating the treestate when
 945:     * a nodes expanded state changes.
 946:     * 
 947:     * @return the TreeExpansionListener responsible for updating the treestate
 948:     */
 949:    protected TreeExpansionListener createTreeExpansionListener()
 950:    {
 951:       return new TreeExpansionHandler();
 952:    }
 953: 
 954:    /**
 955:     * Creates the object responsible for managing what is expanded, as well as
 956:     * the size of nodes.
 957:     * 
 958:     * @return the object responsible for managing what is expanded.
 959:     */
 960:    protected AbstractLayoutCache createLayoutCache()
 961:    {
 962:       return new FixedHeightLayoutCache();
 963:    }
 964: 
 965:    /**
 966:     * Returns the renderer pane that renderer components are placed in.
 967:     * 
 968:     * @return the rendererpane that render components are placed in.
 969:     */
 970:    protected CellRendererPane createCellRendererPane()
 971:    {
 972:       return new CellRendererPane();
 973:    }
 974: 
 975:    /**
 976:     * Creates a default cell editor.
 977:     * 
 978:     * @return the default cell editor.
 979:     */
 980:    protected TreeCellEditor createDefaultCellEditor()
 981:    {
 982:       return new DefaultTreeCellEditor(tree,
 983:             (DefaultTreeCellRenderer) createDefaultCellRenderer(), cellEditor);
 984:    }
 985: 
 986:    /**
 987:     * Returns the default cell renderer that is used to do the stamping of each
 988:     * node.
 989:     * 
 990:     * @return the default cell renderer that is used to do the stamping of each
 991:     *         node.
 992:     */
 993:    protected TreeCellRenderer createDefaultCellRenderer()
 994:    {
 995:       return new DefaultTreeCellRenderer();
 996:    }
 997: 
 998:    /**
 999:     * Returns a listener that can update the tree when the model changes.
1000:     * 
1001:     * @return a listener that can update the tree when the model changes.
1002:     */
1003:    protected TreeModelListener createTreeModelListener()
1004:    {
1005:       return new TreeModelHandler();
1006:    }
1007: 
1008:    /**
1009:     * Uninstall all registered listeners
1010:     */
1011:    protected void uninstallListeners()
1012:    {
1013:       tree.removePropertyChangeListener(propertyChangeListener);
1014:       tree.removeFocusListener(focusListener);
1015:       tree.removeTreeSelectionListener(treeSelectionListener);
1016:       tree.removeMouseListener(mouseInputListener);
1017:       tree.removeKeyListener(keyListener);
1018:       tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1019:       tree.removeComponentListener(componentListener);
1020:       tree.getCellEditor().removeCellEditorListener(cellEditorListener);
1021:       tree.removeTreeExpansionListener(treeExpansionListener);
1022:       tree.getModel().removeTreeModelListener(treeModelListener);
1023:    }
1024: 
1025:    /**
1026:     * Uninstall all keyboard actions.
1027:     */
1028:    protected void uninstallKeyboardActions()
1029:    {
1030:    }
1031: 
1032:    /**
1033:     * Uninstall the rendererPane.
1034:     */
1035:    protected void uninstallComponents()
1036:    {
1037:       // FIXME: not implemented
1038:    }
1039: 
1040:    /**
1041:     * The vertical element of legs between nodes starts at the bottom of the
1042:     * parent node by default. This method makes the leg start below that.
1043:     * 
1044:     * @return the vertical leg buffer
1045:     */
1046:    protected int getVerticalLegBuffer()
1047:    {
1048:       // FIXME: not implemented
1049:       return 0;
1050:    }
1051: 
1052:    /**
1053:     * The horizontal element of legs between nodes starts at the right of the
1054:     * left-hand side of the child node by default. This method makes the leg end
1055:     * before that.
1056:     * 
1057:     * @return the horizontal leg buffer
1058:     */
1059:    protected int getHorizontalLegBuffer()
1060:    {
1061:       // FIXME: not implemented
1062:       return 0;
1063:    }
1064: 
1065:    /**
1066:     * Make all the nodes that are expanded in JTree expanded in LayoutCache.
1067:     * This invokes update ExpandedDescendants with the root path.
1068:     */
1069:    protected void updateLayoutCacheExpandedNodes()
1070:    {
1071:       // FIXME: not implemented
1072:    }
1073: 
1074:    /**
1075:     * Updates the expanded state of all the descendants of the <code>path</code>
1076:     * by getting the expanded descendants from the tree and forwarding to the
1077:     * tree state.
1078:     * 
1079:     * @param path the path used to update the expanded states
1080:     */
1081:    protected void updateExpandedDescendants(TreePath path)
1082:    {
1083:       // FIXME: not implemented
1084:    }
1085: 
1086:    /**
1087:     * Returns a path to the last child of <code>parent</code>
1088:     * 
1089:     * @param parent is the topmost path to specified
1090:     * @return a path to the last child of parent
1091:     */
1092:    protected TreePath getLastChildPath(TreePath parent)
1093:    {
1094:       return ((TreePath) parent.getLastPathComponent());
1095:    }
1096: 
1097:    /**
1098:     * Updates how much each depth should be offset by.
1099:     */
1100:    protected void updateDepthOffset()
1101:    {
1102:       // FIXME: not implemented
1103:    }
1104: 
1105:    /**
1106:     * Updates the cellEditor based on editability of the JTree that we're
1107:     * contained in. Ig the tree is editable but doesn't have a cellEditor, a
1108:     * basic one will be used.
1109:     */
1110:    protected void updateCellEditor()
1111:    {
1112:       // FIXME: not implemented
1113:    }
1114: 
1115:    /**
1116:     * Messaged from the tree we're in when the renderer has changed.
1117:     */
1118:    protected void updateRenderer()
1119:    {
1120:       // FIXME: not implemented
1121:    }
1122: 
1123:    /**
1124:     * Resets the treeState instance based on the tree we're providing the look
1125:     * and feel for.
1126:     */
1127:    protected void configureLayoutCache()
1128:    {
1129:       treeState = createLayoutCache();
1130:    }
1131: 
1132:    /**
1133:     * Marks the cached size as being invalid, and messages the tree with
1134:     * <code>treeDidChange</code>.
1135:     */
1136:    protected void updateSize()
1137:    {
1138:       // FIXME: not implemented
1139:    }
1140: 
1141:    /**
1142:     * Updates the <code>preferredSize</code> instance variable, which is
1143:     * returned from <code>getPreferredSize()</code>. For left to right
1144:     * orientations, the size is determined from the current AbstractLayoutCache.
1145:     * For RTL orientations, the preferred size becomes the width minus the
1146:     * minimum x position.
1147:     */
1148:    protected void updateCachedPreferredSize()
1149:    {
1150:       // FIXME: not implemented
1151:    }
1152: 
1153:    /**
1154:     * Messaged from the VisibleTreeNode after it has been expanded.
1155:     * 
1156:     * @param path is the path that has been expanded.
1157:     */
1158:    protected void pathWasExpanded(TreePath path)
1159:    {
1160:       // FIXME: not implemented
1161:    }
1162: 
1163:    /**
1164:     * Messaged from the VisibleTreeNode after it has collapsed
1165:     */
1166:    protected void pathWasCollapsed(TreePath path)
1167:    {
1168:       // FIXME: not implemented
1169:    }
1170: 
1171:    /**
1172:     * Install all defaults for the tree.
1173:     * 
1174:     * @param tree is the JTree to install defaults for
1175:     */
1176:    protected void installDefaults(JTree tree)
1177:    {
1178:       UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1179: 
1180:       tree.setFont(defaults.getFont("Tree.font"));
1181:       tree.setForeground(defaults.getColor("Tree.foreground"));
1182:       tree.setBackground(defaults.getColor("Tree.background"));
1183:       tree.setOpaque(true);
1184: 
1185:       rightChildIndent = defaults.getInt("Tree.rightChildIndent");
1186:       leftChildIndent = defaults.getInt("Tree.leftChildIndent");
1187:       setRowHeight(defaults.getInt("Tree.rowHeight"));
1188:    }
1189: 
1190:    /**
1191:     * Install all keyboard actions for this
1192:     */
1193:    protected void installKeyboardActions()
1194:    {
1195:    }
1196: 
1197:    /**
1198:     * Install all listeners for this
1199:     */
1200:    protected void installListeners()
1201:    {
1202:       tree.addPropertyChangeListener(propertyChangeListener);
1203:       tree.addFocusListener(focusListener);
1204:       tree.addTreeSelectionListener(treeSelectionListener);
1205:       tree.addMouseListener(mouseInputListener);
1206:       tree.addKeyListener(keyListener);
1207:       tree.addPropertyChangeListener(selectionModelPropertyChangeListener);
1208:       tree.addComponentListener(componentListener);
1209:       cellEditor.addCellEditorListener(cellEditorListener);
1210:       tree.addTreeExpansionListener(treeExpansionListener);
1211:       treeModel.addTreeModelListener(treeModelListener);
1212:    }
1213: 
1214:    /**
1215:     * Install the UI for the component
1216:     * 
1217:     * @param c the component to install UI for
1218:     */
1219:    public void installUI(JComponent c)
1220:    {
1221:       super.installUI(c);
1222:       installDefaults((JTree) c);
1223:       tree = (JTree) c;
1224:       setModel(tree.getModel());
1225:       tree.setRootVisible(true);
1226:       tree.expandPath(new TreePath(((DefaultMutableTreeNode) 
1227:             (tree.getModel()).getRoot()).getPath()));
1228:       treeSelectionModel = tree.getSelectionModel();
1229:       installListeners();
1230:       installKeyboardActions();
1231:       completeUIInstall();
1232:    }
1233: 
1234:    /**
1235:     * Uninstall the defaults for the tree
1236:     * 
1237:     * @param tree to uninstall defaults for
1238:     */
1239:    protected void uninstallDefaults(JTree tree)
1240:    {
1241:       UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1242:       tree.setFont(null);
1243:       tree.setForeground(null);
1244:       tree.setBackground(null);
1245:       tree.setCellRenderer(null);
1246:    }
1247: 
1248:    /**
1249:     * Uninstall the UI for the component
1250:     * 
1251:     * @param c the component to uninstall UI for
1252:     */
1253:    public void uninstallUI(JComponent c)
1254:    {
1255:       uninstallDefaults((JTree) c);
1256:       uninstallKeyboardActions();
1257:       uninstallListeners();
1258:       tree = null;
1259:       completeUIUninstall();
1260:    }
1261: 
1262:    /**
1263:     * Paints the specified component appropriate for the look and feel. This
1264:     * method is invoked from the ComponentUI.update method when the specified
1265:     * component is being painted. Subclasses should override this method and use
1266:     * the specified Graphics object to render the content of the component.
1267:     * 
1268:     * @param g the Graphics context in which to paint
1269:     * @param c the component being painted; this argument is often ignored, but
1270:     *        might be used if the UI object is stateless and shared by multiple
1271:     *        components
1272:     */
1273:    public void paint(Graphics g, JComponent c)
1274:    {
1275:       JTree tree = (JTree) c;
1276:       TreeModel mod = tree.getModel();
1277:       g.translate(10, 10);
1278:       paintRecursive(g, 0, 0, 0, 0, tree, mod, mod.getRoot());
1279:       paintControlIcons(g, 0, 0, 0, 0, tree, mod, mod.getRoot());
1280:       g.translate(-10, -10);
1281:    }
1282: 
1283:    /**
1284:     * Ensures that the rows identified by beginRow through endRow are visible.
1285:     * 
1286:     * @param beginRow is the first row
1287:     * @param endRow is the last row
1288:     */
1289:    protected void ensureRowsAreVisible(int beginRow, int endRow)
1290:    {
1291:       // FIXME: not implemented
1292:    }
1293: 
1294:    /**
1295:     * Sets the preferred minimum size.
1296:     * 
1297:     * @param newSize is the new preferred minimum size.
1298:     */
1299:    public void setPreferredMinSize(Dimension newSize)
1300:    {
1301:       // FIXME: not implemented
1302:    }
1303: 
1304:    /**
1305:     * Gets the preferred minimum size.
1306:     * 
1307:     * @returns the preferred minimum size.
1308:     */
1309:    public Dimension getPreferredMinSize()
1310:    {
1311:       // FIXME: not implemented
1312:       return null;
1313:    }
1314: 
1315:    /**
1316:     * Returns the preferred size to properly display the tree, this is a cover
1317:     * method for getPreferredSize(c, false).
1318:     * 
1319:     * @param c the component whose preferred size is being queried; this
1320:     *        argument is often ignored but might be used if the UI object is
1321:     *        stateless and shared by multiple components
1322:     * @return the preferred size
1323:     */
1324:    public Dimension getPreferredSize(JComponent c)
1325:    {
1326:       return getPreferredSize(c, false);
1327:    }
1328: 
1329:    /**
1330:     * Returns the preferred size to represent the tree in c. If checkConsistancy
1331:     * is true, checkConsistancy is messaged first.
1332:     * 
1333:     * @param c the component whose preferred size is being queried.
1334:     * @param checkConsistancy if true must check consistancy
1335:     * @return the preferred size
1336:     */
1337:    public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1338:    {
1339:       // FIXME: checkConsistancy not implemented, c not used
1340:       DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel())
1341:             .getRoot());
1342:       int maxWidth = 0;
1343:       int count = 0;
1344:       if (node != null)
1345:       {
1346:          maxWidth = (int) (getCellBounds(0, 0, node).getWidth());
1347:          while (node != null)
1348:          {
1349:             count++;
1350:             DefaultMutableTreeNode nextNode = node.getNextNode();
1351:             if (nextNode != null)
1352:                maxWidth = Math.max(maxWidth, (int) (getCellBounds(0, 0, nextNode)
1353:                      .getWidth()));
1354:             node = nextNode;
1355:          }
1356:       }
1357:       
1358:       return new Dimension(maxWidth, (getRowHeight() * count));
1359:    }
1360: 
1361:    /**
1362:     * Returns the minimum size for this component. Which will be the min
1363:     * preferred size or (0,0).
1364:     * 
1365:     * @param c the component whose min size is being queried.
1366:     * @returns the preferred size or null
1367:     */
1368:    public Dimension getMinimumSize(JComponent c)
1369:    {
1370:       // FIXME: not implemented
1371:       return getPreferredSize(c);
1372:    }
1373: 
1374:    /**
1375:     * Returns the maximum size for the component, which will be the preferred
1376:     * size if the instance is currently in JTree or (0,0).
1377:     * 
1378:     * @param c the component whose preferred size is being queried
1379:     * @return the max size or null
1380:     */
1381:    public Dimension getMaximumSize(JComponent c)
1382:    {
1383:       // FIXME: not implemented
1384:       return getPreferredSize(c);
1385:    }
1386: 
1387:    /**
1388:     * Messages to stop the editing session. If the UI the receiver is providing
1389:     * the look and feel for returns true from
1390:     * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked
1391:     * on the current editor. Then completeEditing will be messaged with false,
1392:     * true, false to cancel any lingering editing.
1393:     */
1394:    protected void completeEditing()
1395:    {
1396:       // FIXME: not implemented
1397:    }
1398: 
1399:    /**
1400:     * Stops the editing session. If messageStop is true, the editor is messaged
1401:     * with stopEditing, if messageCancel is true the editor is messaged with
1402:     * cancelEditing. If messageTree is true, the treeModel is messaged with
1403:     * valueForPathChanged.
1404:     * 
1405:     * @param messageStop message to stop editing
1406:     * @param messageCancel message to cancel editing
1407:     * @param messageTree message to treeModel
1408:     */
1409:    protected void completeEditing(boolean messageStop, boolean messageCancel,
1410:          boolean messageTree)
1411:    {
1412:       // FIXME: not implemented
1413:    }
1414: 
1415:    /**
1416:     * Will start editing for node if there is a cellEditor and shouldSelectCall
1417:     * returns true. This assumes that path is valid and visible.
1418:     * 
1419:     * @param path is the path to start editing
1420:     * @param event is the MouseEvent performed on the path
1421:     * @return true if successful
1422:     */
1423:    protected boolean startEditing(TreePath path, MouseEvent event)
1424:    {
1425:       // FIXME: not implemented
1426:       return false;
1427:    }
1428: 
1429:    /**
1430:     * If the <code>mouseX</code> and <code>mouseY</code> are in the expand
1431:     * or collapse region of the row, this will toggle the row.
1432:     * 
1433:     * @param path the path we are concerned with
1434:     * @param mouseX is the cursor's x position
1435:     * @param mouseY is the cursor's y position
1436:     */
1437:    protected void checkForClickInExpandControl(TreePath path, int mouseX,
1438:          int mouseY)
1439:    {
1440:       // FIXME: not implemented
1441:    }
1442: 
1443:    /**
1444:     * Returns true if the <code>mouseX</code> and <code>mouseY</code> fall
1445:     * in the area of row that is used to expand/collpse the node and the node at
1446:     * row does not represent a leaf.
1447:     * 
1448:     * @param path the path we are concerned with
1449:     * @param mouseX is the cursor's x position
1450:     * @param mouseY is the cursor's y position
1451:     * @return true if the <code>mouseX</code> and <code>mouseY</code> fall
1452:     *         in the area of row that is used to expand/collpse the node and the
1453:     *         node at row does not represent a leaf.
1454:     */
1455:    protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1456:          int mouseY)
1457:    {
1458:       // FIXME: not implemented
1459:       return false;
1460:    }
1461: 
1462:    /**
1463:     * Messaged when the user clicks the particular row, this invokes
1464:     * toggleExpandState.
1465:     * 
1466:     * @param path the path we are concerned with
1467:     * @param mouseX is the cursor's x position
1468:     * @param mouseY is the cursor's y position
1469:     */
1470:    protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1471:    {
1472:       // FIXME: not implemented
1473:    }
1474: 
1475:    /**
1476:     * Expands path if it is not expanded, or collapses row if it is expanded. If
1477:     * expanding a path and JTree scroll on expand, ensureRowsAreVisible is
1478:     * invoked to scroll as many of the children to visible as possible (tries to
1479:     * scroll to last visible descendant of path).
1480:     * 
1481:     * @param path the path we are concerned with
1482:     */
1483:    protected void toggleExpandState(TreePath path)
1484:    {
1485:       // FIXME: not implemented
1486:    }
1487: 
1488:    /**
1489:     * Returning true signifies a mouse event on the node should toggle the
1490:     * selection of only the row under the mouse.
1491:     * 
1492:     * @param event is the MouseEvent performed on the row.
1493:     * @return true signifies a mouse event on the node should toggle the
1494:     *         selection of only the row under the mouse.
1495:     */
1496:    protected boolean isToggleSelectionEvent(MouseEvent event)
1497:    {
1498:       // FIXME: not implemented
1499:       return false;
1500:    }
1501: 
1502:    /**
1503:     * Returning true signifies a mouse event on the node should select from the
1504:     * anchor point.
1505:     * 
1506:     * @param event is the MouseEvent performed on the node.
1507:     * @return true signifies a mouse event on the node should select from the
1508:     *         anchor point.
1509:     */
1510:    protected boolean isMultiSelectEvent(MouseEvent event)
1511:    {
1512:       // FIXME: not implemented
1513:       return false;
1514:    }
1515: 
1516:    /**
1517:     * Returning true indicates the row under the mouse should be toggled based
1518:     * on the event. This is invoked after checkForClickInExpandControl, implying
1519:     * the location is not in the expand (toggle) control.
1520:     * 
1521:     * @param event is the MouseEvent performed on the row.
1522:     * @return true indicates the row under the mouse should be toggled based on
1523:     *         the event.
1524:     */
1525:    protected boolean isToggleEvent(MouseEvent event)
1526:    {
1527:       // FIXME: not implemented
1528:       return false;
1529:    }
1530: 
1531:    /**
1532:     * Messaged to update the selection based on a MouseEvent over a particular
1533:     * row. If the even is a toggle selection event, the row is either selected,
1534:     * or deselected. If the event identifies a multi selection event, the
1535:     * selection is updated from the anchor point. Otherwise, the row is
1536:     * selected, and if the even specified a toggle event the row is
1537:     * expanded/collapsed.
1538:     * 
1539:     * @param path is the path selected for an event
1540:     * @param event is the MouseEvent performed on the path.
1541:     */
1542:    protected void selectPathForEvent(TreePath path, MouseEvent event)
1543:    {
1544:       // FIXME: not implemented
1545:    }
1546: 
1547:    /**
1548:     * Returns true if the node at <code>row</code> is a leaf.
1549:     * 
1550:     * @param row is the row we are concerned with.
1551:     * @return true if the node at <code>row</code> is a leaf.
1552:     */
1553:    protected boolean isLeaf(int row)
1554:    {
1555:       TreePath pathForRow = getPathForRow(tree, row);
1556:       if (pathForRow == null)
1557:          return true;
1558: 
1559:       Object node = pathForRow.getLastPathComponent();
1560: 
1561:       if (node instanceof TreeNode)
1562:          return ((TreeNode) node).isLeaf();
1563:       else
1564:          return true;
1565:    }
1566: 
1567:    /**
1568:     * Selects the specified path in the tree depending on modes.
1569:     * Package private for use in inner classes.
1570:     * 
1571:     * @param tree is the tree we are selecting the path in
1572:     * @param path is the path we are selecting
1573:     */
1574:    void selectPath(JTree tree, TreePath path)
1575:    {
1576:       if (path != null)
1577:       {
1578:          if (tree.isPathSelected(path))
1579:             tree.removeSelectionPath(path);
1580:          else if (tree.getSelectionModel().getSelectionMode() 
1581:                == TreeSelectionModel.SINGLE_TREE_SELECTION)
1582:          {
1583:             tree.getSelectionModel().clearSelection();
1584:             tree.addSelectionPath(path);
1585:             tree.setLeadSelectionPath(path);
1586:          }
1587:          else if (tree.getSelectionModel().getSelectionMode() 
1588:                == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
1589:          {
1590:             // TODO
1591:          }
1592:          else
1593:          {
1594:             tree.getSelectionModel().setSelectionMode(
1595:                   TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
1596:             tree.addSelectionPath(path);
1597:             tree.setLeadSelectionPath(path);
1598:          }
1599:       }
1600:    }
1601:    
1602:    /* * INTERNAL CLASSES * */
1603: 
1604:    /**
1605:     * Updates the preferred size when scrolling, if necessary.
1606:     */
1607:    public class ComponentHandler
1608:          extends ComponentAdapter
1609:          implements ActionListener
1610:    {
1611:       /**
1612:        * Timer used when inside a scrollpane and the scrollbar is adjusting
1613:        */
1614:       protected Timer timer;
1615: 
1616:       /** ScrollBar that is being adjusted */
1617:       protected JScrollBar scrollBar;
1618: 
1619:       /**
1620:        * Constructor
1621:        */
1622:       public ComponentHandler()
1623:       {
1624:       }
1625: 
1626:       /**
1627:        * Invoked when the component's position changes.
1628:        * 
1629:        * @param e the event that occurs when moving the component
1630:        */
1631:       public void componentMoved(ComponentEvent e)
1632:       {
1633:       }
1634: 
1635:       /**
1636:        * Creats, if necessary, and starts a Timer to check if needed to resize
1637:        * the bounds
1638:        */
1639:       protected void startTimer()
1640:       {
1641:       }
1642: 
1643:       /**
1644:        * Returns the JScrollPane housing the JTree, or null if one isn't found.
1645:        * 
1646:        * @return JScrollPane housing the JTree, or null if one isn't found.
1647:        */
1648:       protected JScrollPane getScrollPane()
1649:       {
1650:          return null;
1651:       }
1652: 
1653:       /**
1654:        * Public as a result of Timer. If the scrollBar is null, or not
1655:        * adjusting, this stops the timer and updates the sizing.
1656:        * 
1657:        * @param ae is the action performed
1658:        */
1659:       public void actionPerformed(ActionEvent ae)
1660:       {
1661:       }
1662:    }// ComponentHandler
1663: 
1664:    /**
1665:     * Listener responsible for getting cell editing events and updating the tree
1666:     * accordingly.
1667:     */
1668:    public class CellEditorHandler
1669:          implements CellEditorListener
1670:    {
1671:       /**
1672:        * Constructor
1673:        */
1674:       public CellEditorHandler()
1675:       {
1676:       }
1677: 
1678:       /**
1679:        * Messaged when editing has stopped in the tree. Tells the listeners
1680:        * editing has stopped.
1681:        * 
1682:        * @param e is the notification event
1683:        */
1684:       public void editingStopped(ChangeEvent e)
1685:       {
1686:       }
1687: 
1688:       /**
1689:        * Messaged when editing has been canceled in the tree. This tells the
1690:        * listeners the editor has canceled editing.
1691:        * 
1692:        * @param e is the notification event
1693:        */
1694:       public void editingCanceled(ChangeEvent e)
1695:       {
1696:       }
1697:    }// CellEditorHandler
1698: 
1699:    /**
1700:     * Repaints the lead selection row when focus is lost/grained.
1701:     */
1702:    public class FocusHandler
1703:          implements FocusListener
1704:    {
1705:       /**
1706:        * Constructor
1707:        */
1708:       public FocusHandler()
1709:       {
1710:       }
1711: 
1712:       /**
1713:        * Invoked when focus is activated on the tree we're in, redraws the lead
1714:        * row. Invoked when a component gains the keyboard focus.
1715:        * 
1716:        * @param e is the focus event that is activated
1717:        */
1718:       public void focusGained(FocusEvent e)
1719:       {
1720:       }
1721: 
1722:       /**
1723:        * Invoked when focus is deactivated on the tree we're in, redraws the
1724:        * lead row. Invoked when a component loses the keyboard focus.
1725:        * 
1726:        * @param e is the focus event that is deactivated
1727:        */
1728:       public void focusLost(FocusEvent e)
1729:       {
1730:       }
1731:    }// FocusHandler
1732: 
1733:    /**
1734:     * This is used to get multiple key down events to appropriately genereate
1735:     * events.
1736:     */
1737:    public class KeyHandler
1738:          extends KeyAdapter
1739:    {
1740:       /** Key code that is being generated for. */
1741:       protected Action repeatKeyAction;
1742: 
1743:       /** Set to true while keyPressed is active */
1744:       protected boolean isKeyDown;
1745: 
1746:       /**
1747:        * Constructor
1748:        */
1749:       public KeyHandler()
1750:       {
1751:       }
1752: 
1753:       /**
1754:        * Invoked when a key has been typed. Moves the keyboard focus to the
1755:        * first element whose first letter matches the alphanumeric key pressed
1756:        * by the user. Subsequent same key presses move the keyboard focus to the
1757:        * next object that starts with the same letter.
1758:        * 
1759:        * @param e the key typed
1760:        */
1761:       public void keyTyped(KeyEvent e)
1762:       {
1763:       }
1764: 
1765:       /**
1766:        * Invoked when a key has been pressed.
1767:        * 
1768:        * @param e the key pressed
1769:        */
1770:       public void keyPressed(KeyEvent e)
1771:       {         
1772:          TreePath start = BasicTreeUI.this.tree.getLeadSelectionPath();
1773:          DefaultMutableTreeNode last = null;
1774:          
1775:          if (start != null)
1776:             last = (DefaultMutableTreeNode) start.getLastPathComponent();
1777:          if (last != null)
1778:          {
1779:             if (e.getKeyCode() == KeyEvent.VK_DOWN)
1780:             {
1781:                DefaultMutableTreeNode next = (DefaultMutableTreeNode) 
1782:                   BasicTreeUI.this.getNextVisibleNode(last);
1783:                
1784:                if (next != null)
1785:                   BasicTreeUI.this.selectPath(BasicTreeUI.this.tree,
1786:                         new TreePath(next.getPath()));
1787:             }
1788:             else if (e.getKeyCode() == KeyEvent.VK_UP)
1789:             {
1790:                DefaultMutableTreeNode prev = (DefaultMutableTreeNode) 
1791:                BasicTreeUI.this.getPreviousVisibleNode(last);
1792:             
1793:             if (prev != null)
1794:                BasicTreeUI.this.selectPath(BasicTreeUI.this.tree,
1795:                      new TreePath(prev.getPath()));
1796:             }
1797:             else if (e.getKeyCode() == KeyEvent.VK_LEFT)
1798:             {
1799:                TreePath path = new TreePath(last.getPath());
1800:                
1801:                if (!last.isLeaf() && BasicTreeUI.this.tree.isExpanded(path))
1802:                {
1803:                   BasicTreeUI.this.tree.collapsePath(path);
1804:                   BasicTreeUI.this.tree.fireTreeCollapsed(path);
1805:                }
1806:             }
1807:             else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
1808:             {
1809:                TreePath path = new TreePath(last.getPath());
1810:    
1811:                if (!last.isLeaf() && BasicTreeUI.this.tree.isCollapsed(path))
1812:                {
1813:                   BasicTreeUI.this.tree.expandPath(path);
1814:                   BasicTreeUI.this.tree.fireTreeExpanded(path);
1815:                }
1816:             }
1817:          }
1818:       }
1819: 
1820:       /**
1821:        * Invoked when a key has been released
1822:        * 
1823:        * @param e the key released
1824:        */
1825:       public void keyReleased(KeyEvent e)
1826:       {
1827:       }
1828:    }// KeyHandler
1829: 
1830:    /**
1831:     * MouseListener is responsible for updating the selevtion based on mouse
1832:     * events.
1833:     */
1834:    public class MouseHandler
1835:          extends MouseAdapter
1836:          implements MouseMotionListener
1837:    {
1838:       /**
1839:        * Constructor
1840:        */
1841:       public MouseHandler()
1842:       {
1843:       }
1844: 
1845:       /**
1846:        * Invoked when a mouse button has been pressed on a component.
1847:        * 
1848:        * @param e is the mouse event that occured
1849:        */
1850:       public void mousePressed(MouseEvent e)
1851:       {
1852:       }
1853: 
1854:       /**
1855:        * Invoked when a mouse button is pressed on a component and then dragged.
1856:        * MOUSE_DRAGGED events will continue to be delivered to the component
1857:        * where the drag originated until the mouse button is released
1858:        * (regardless of whether the mouse position is within the bounds of the
1859:        * component).
1860:        * 
1861:        * @param e is the mouse event that occured
1862:        */
1863:       public void mouseDragged(MouseEvent e)
1864:       {
1865:       }
1866: 
1867:       /**
1868:        * Invoked when the mouse button has been moved on a component (with no
1869:        * buttons no down).
1870:        * 
1871:        * @param e the mouse event that occured
1872:        */
1873:       public void mouseMoved(MouseEvent e)
1874:       {
1875:       }
1876: 
1877:       /**
1878:        * Invoked when a mouse button has been released on a component.
1879:        * 
1880:        * @param e is the mouse event that occured
1881:        */
1882:       public void mouseReleased(MouseEvent e)
1883:       {
1884:       }
1885:    }// MouseHandler
1886: 
1887:    /**
1888:     * MouseInputHandler handles passing all mouse events, including mouse motion
1889:     * events, until the mouse is released to the destination it is constructed
1890:     * with.
1891:     */
1892:    public class MouseInputHandler
1893:          implements MouseInputListener
1894:    {
1895:       /** Source that events are coming from */
1896:       protected Component source;
1897: 
1898:       /** Destination that receives all events. */
1899:       protected Component destination;
1900:       
1901:       /** Number of mouse clicks on a non-leaf */
1902:       private int clickCount = 0;
1903: 
1904:       /**
1905:        * Constructor
1906:        * 
1907:        * @param source that events are coming from
1908:        * @param destination that receives all events
1909:        * @param event is the event received
1910:        */
1911:       public MouseInputHandler(Component source, Component destination,
1912:             MouseEvent e)
1913:       {
1914:       }
1915: 
1916:       /**
1917:        * Invoked when the mouse button has been clicked (pressed and released)
1918:        * on a component.
1919:        * 
1920:        * @param e mouse event that occured
1921:        */
1922:       public void mouseClicked(MouseEvent e)
1923:       {
1924:          Point click = e.getPoint();
1925:          int row = ((int) click.getY() / getRowHeight()) - 1;
1926:          TreePath path = BasicTreeUI.this.tree.getPathForRow(row);
1927: 
1928:          if (path == null)
1929:          {
1930:             // nothing should be selected if user clicks outside of tree
1931:             BasicTreeUI.this.tree.getSelectionModel().clearSelection();
1932:             BasicTreeUI.this.tree.repaint();
1933:          }
1934:          else if (BasicTreeUI.this.tree.isVisible(path))
1935:          {           
1936:             if (!BasicTreeUI.this.isLeaf(row))
1937:                clickCount++;
1938:             
1939:             if (clickCount == 2)
1940:             {
1941:                BasicTreeUI.this.tree.getSelectionModel().clearSelection();
1942:                clickCount = 0;
1943:                if (BasicTreeUI.this.tree.isExpanded(path))
1944:                {
1945:                   BasicTreeUI.this.tree.collapsePath(path);
1946:                   BasicTreeUI.this.tree.fireTreeCollapsed(path);
1947:                }
1948:                else
1949:                {
1950:                   BasicTreeUI.this.tree.expandPath(path);
1951:                   BasicTreeUI.this.tree.fireTreeExpanded(path);
1952:                }
1953:             }
1954: 
1955:             BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, path);
1956:          }
1957:       }
1958: 
1959:       /**
1960:        * Invoked when a mouse button has been pressed on a component.
1961:        * 
1962:        * @param e mouse event that occured
1963:        */
1964:       public void mousePressed(MouseEvent e)
1965:       {
1966:       }
1967: 
1968:       /**
1969:        * Invoked when a mouse button has been released on a component.
1970:        * 
1971:        * @param e mouse event that occured
1972:        */
1973:       public void mouseReleased(MouseEvent e)
1974:       {
1975:       }
1976: 
1977:       /**
1978:        * Invoked when the mouse enters a component.
1979:        * 
1980:        * @param e mouse event that occured
1981:        */
1982:       public void mouseEntered(MouseEvent e)
1983:       {
1984:       }
1985: 
1986:       /**
1987:        * Invoked when the mouse exits a component.
1988:        * 
1989:        * @param e mouse event that occured
1990:        */
1991:       public void mouseExited(MouseEvent e)
1992:       {
1993:       }
1994: 
1995:       /**
1996:        * Invoked when a mouse button is pressed on a component and then dragged.
1997:        * MOUSE_DRAGGED events will continue to be delivered to the component
1998:        * where the drag originated until the mouse button is released
1999:        * (regardless of whether the mouse position is within the bounds of the
2000:        * component).
2001:        * 
2002:        * @param e mouse event that occured
2003:        */
2004:       public void mouseDragged(MouseEvent e)
2005:       {
2006:       }
2007: 
2008:       /**
2009:        * Invoked when the mouse cursor has been moved onto a component but no
2010:        * buttons have been pushed.
2011:        * 
2012:        * @param e mouse event that occured
2013:        */
2014:       public void mouseMoved(MouseEvent e)
2015:       {
2016:       }
2017: 
2018:       /**
2019:        * Removes event from the source
2020:        */
2021:       protected void removeFromSource()
2022:       {
2023:       }
2024:    }// MouseInputHandler
2025: 
2026:    /**
2027:     * Class responsible for getting size of node, method is forwarded to
2028:     * BasicTreeUI method. X location does not include insets, that is handled in
2029:     * getPathBounds.
2030:     */
2031:    public class NodeDimensionsHandler
2032:          extends AbstractLayoutCache.NodeDimensions
2033:    {
2034:       /**
2035:        * Constructor
2036:        */
2037:       public NodeDimensionsHandler()
2038:       {
2039:       }
2040: 
2041:       /**
2042:        * Responsible for getting the size of a particular node.
2043:        * 
2044:        * @param value the value to be represented
2045:        * @param row row being queried
2046:        * @param depth the depth of the row
2047:        * @param expanded true if row is expanded
2048:        * @param size a Rectangle containing the size needed to represent value
2049:        * @return containing the node dimensions, or null if node has no
2050:        *         dimension
2051:        */
2052:       public Rectangle getNodeDimensions(Object value, int row, int depth,
2053:             boolean expanded, Rectangle size)
2054:       {
2055:          return null;
2056:       }
2057: 
2058:       /**
2059:        * Returns the amount to indent the given row
2060:        * 
2061:        * @return amount to indent the given row.
2062:        */
2063:       protected int getRowX(int row, int depth)
2064:       {
2065:          return 0;
2066:       }
2067:    }// NodeDimensionsHandler
2068: 
2069:    /**
2070:     * PropertyChangeListener for the tree. Updates the appropriate varaible, or
2071:     * TreeState, based on what changes.
2072:     */
2073:    public class PropertyChangeHandler
2074:          implements PropertyChangeListener
2075:    {
2076: 
2077:       /**
2078:        * Constructor
2079:        */
2080:       public PropertyChangeHandler()
2081:       {
2082:       }
2083: 
2084:       /**
2085:        * This method gets called when a bound property is changed.
2086:        * 
2087:        * @param event A PropertyChangeEvent object describing the event source
2088:        *        and the property that has changed.
2089:        */
2090:       public void propertyChange(PropertyChangeEvent event)
2091:       {
2092:       }
2093:    }// PropertyChangeHandler
2094: 
2095:    /**
2096:     * Listener on the TreeSelectionModel, resets the row selection if any of the
2097:     * properties of the model change.
2098:     */
2099:    public class SelectionModelPropertyChangeHandler
2100:          implements PropertyChangeListener
2101:    {
2102: 
2103:       /**
2104:        * Constructor
2105:        */
2106:       public SelectionModelPropertyChangeHandler()
2107:       {
2108:       }
2109: 
2110:       /**
2111:        * This method gets called when a bound property is changed.
2112:        * 
2113:        * @param event A PropertyChangeEvent object describing the event source
2114:        *        and the property that has changed.
2115:        */
2116:       public void propertyChange(PropertyChangeEvent event)
2117:       {
2118:       }
2119:    }// SelectionModelPropertyChangeHandler
2120: 
2121:    /**
2122:     * ActionListener that invokes cancelEditing when action performed.
2123:     */
2124:    public class TreeCancelEditingAction
2125:          extends AbstractAction
2126:    {
2127: 
2128:       /**
2129:        * Constructor
2130:        */
2131:       public TreeCancelEditingAction()
2132:       {
2133:       }
2134: 
2135:       /**
2136:        * Invoked when an action occurs.
2137:        * 
2138:        * @param e event that occured
2139:        */
2140:       public void actionPerformed(ActionEvent e)
2141:       {
2142:       }
2143: 
2144:       /**
2145:        * Returns true if the action is enabled.
2146:        * 
2147:        * @return true if the action is enabled, false otherwise
2148:        */
2149:       public boolean isEnabled()
2150:       {
2151:          return false;
2152:       }
2153:    }// TreeCancelEditingAction
2154: 
2155:    /**
2156:     * Updates the TreeState in response to nodes expanding/collapsing.
2157:     */
2158:    public class TreeExpansionHandler
2159:          implements TreeExpansionListener
2160:    {
2161: 
2162:       /**
2163:        * Constructor
2164:        */
2165:       public TreeExpansionHandler()
2166:       {
2167:       }
2168: 
2169:       /**
2170:        * Called whenever an item in the tree has been expanded.
2171:        * 
2172:        * @param event is the event that occured
2173:        */
2174:       public void treeExpanded(TreeExpansionEvent event)
2175:       {
2176:          BasicTreeUI.this.tree.repaint();
2177:       }
2178: 
2179:       /**
2180:        * Called whenever an item in the tree has been collapsed.
2181:        * 
2182:        * @param event is the event that occured
2183:        */
2184:       public void treeCollapsed(TreeExpansionEvent event)
2185:       {
2186:          BasicTreeUI.this.tree.repaint();
2187:       }
2188:    }// TreeExpansionHandler
2189: 
2190:    /**
2191:     * TreeHomeAction is used to handle end/home actions. Scrolls either the
2192:     * first or last cell to be visible based on direction.
2193:     */
2194:    public class TreeHomeAction
2195:          extends AbstractAction
2196:    {
2197: 
2198:       /** direction is either home or end */
2199:       protected int direction;
2200: 
2201:       /**
2202:        * Constructor
2203:        * 
2204:        * @param direction - it is home or end
2205:        * @param name is the name of the direction
2206:        */
2207:       public TreeHomeAction(int direction, String name)
2208:       {
2209:       }
2210: 
2211:       /**
2212:        * Invoked when an action occurs.
2213:        * 
2214:        * @param e is the event that occured
2215:        */
2216:       public void actionPerformed(ActionEvent e)
2217:       {
2218:       }
2219: 
2220:       /**
2221:        * Returns true if the action is enabled.
2222:        * 
2223:        * @return true if the action is enabled.
2224:        */
2225:       public boolean isEnabled()
2226:       {
2227:          return false;
2228:       }
2229:    }// TreeHomeAction
2230: 
2231:    /**
2232:     * TreeIncrementAction is used to handle up/down actions. Selection is moved
2233:     * up or down based on direction.
2234:     */
2235:    public class TreeIncrementAction
2236:          extends AbstractAction
2237:    {
2238: 
2239:       /** Specifies the direction to adjust the selection by. */
2240:       protected int direction;
2241: 
2242:       /**
2243:        * Constructor
2244:        * 
2245:        * @param direction up or down
2246:        * @param name is the name of the direction
2247:        */
2248:       public TreeIncrementAction(int direction, String name)
2249:       {
2250:       }
2251: 
2252:       /**
2253:        * Invoked when an action occurs.
2254:        * 
2255:        * @param e is the event that occured
2256:        */
2257:       public void actionPerformed(ActionEvent e)
2258:       {
2259:       }
2260: 
2261:       /**
2262:        * Returns true if the action is enabled.
2263:        * 
2264:        * @return true if the action is enabled.
2265:        */
2266:       public boolean isEnabled()
2267:       {
2268:          return false;
2269:       }
2270:    }// TreeIncrementAction
2271: 
2272:    /**
2273:     * Forwards all TreeModel events to the TreeState.
2274:     */
2275:    public class TreeModelHandler
2276:          implements TreeModelListener
2277:    {
2278:       /**
2279:        * Constructor
2280:        */
2281:       public TreeModelHandler()
2282:       {
2283:       }
2284: 
2285:       /**
2286:        * Invoked after a node (or a set of siblings) has changed in some way.
2287:        * The node(s) have not changed locations in the tree or altered their
2288:        * children arrays, but other attributes have changed and may affect
2289:        * presentation. Example: the name of a file has changed, but it is in the
2290:        * same location in the file system. To indicate the root has changed,
2291:        * childIndices and children will be null. Use e.getPath() to get the
2292:        * parent of the changed node(s). e.getChildIndices() returns the
2293:        * index(es) of the changed node(s).
2294:        * 
2295:        * @param e is the event that occured
2296:        */
2297:       public void treeNodesChanged(TreeModelEvent e)
2298:       {
2299:       }
2300: 
2301:       /**
2302:        * Invoked after nodes have been inserted into the tree. Use e.getPath()
2303:        * to get the parent of the new node(s). e.getChildIndices() returns the
2304:        * index(es) of the new node(s) in ascending order.
2305:        * 
2306:        * @param e is the event that occured
2307:        */
2308:       public void treeNodesInserted(TreeModelEvent e)
2309:       {
2310:       }
2311: 
2312:       /**
2313:        * Invoked after nodes have been removed from the tree. Note that if a
2314:        * subtree is removed from the tree, this method may only be invoked once
2315:        * for the root of the removed subtree, not once for each individual set
2316:        * of siblings removed. Use e.getPath() to get the former parent of the
2317:        * deleted node(s). e.getChildIndices() returns, in ascending order, the
2318:        * index(es) the node(s) had before being deleted.
2319:        * 
2320:        * @param e is the event that occured
2321:        */
2322:       public void treeNodesRemoved(TreeModelEvent e)
2323:       {
2324:       }
2325: 
2326:       /**
2327:        * Invoked after the tree has drastically changed structure from a given
2328:        * node down. If the path returned by e.getPath() is of length one and the
2329:        * first element does not identify the current root node the first element
2330:        * should become the new root of the tree. Use e.getPath() to get the path
2331:        * to the node. e.getChildIndices() returns null.
2332:        * 
2333:        * @param e is the event that occured
2334:        */
2335:       public void treeStructureChanged(TreeModelEvent e)
2336:       {
2337:       }
2338:    }// TreeModelHandler
2339: 
2340:    /**
2341:     * TreePageAction handles page up and page down events.
2342:     */
2343:    public class TreePageAction
2344:          extends AbstractAction
2345:    {
2346:       /** Specifies the direction to adjust the selection by. */
2347:       protected int direction;
2348: 
2349:       /**
2350:        * Constructor
2351:        * 
2352:        * @param direction up or down
2353:        * @param name is the name of the direction
2354:        */
2355:       public TreePageAction(int direction, String name)
2356:       {
2357:       }
2358: 
2359:       /**
2360:        * Invoked when an action occurs.
2361:        * 
2362:        * @param e is the event that occured
2363:        */
2364:       public void actionPerformed(ActionEvent e)
2365:       {
2366:       }
2367: 
2368:       /**
2369:        * Returns true if the action is enabled.
2370:        * 
2371:        * @return true if the action is enabled.
2372:        */
2373:       public boolean isEnabled()
2374:       {
2375:          return false;
2376:       }
2377:    }// TreePageAction
2378: 
2379:    /**
2380:     * Listens for changes in the selection model and updates the display
2381:     * accordingly.
2382:     */
2383:    public class TreeSelectionHandler
2384:          implements TreeSelectionListener
2385:    {
2386:       /**
2387:        * Constructor
2388:        */
2389:       public TreeSelectionHandler()
2390:       {
2391:       }
2392: 
2393:       /**
2394:        * Messaged when the selection changes in the tree we're displaying for.
2395:        * Stops editing, messages super and displays the changed paths.
2396:        * 
2397:        * @param event the event that characterizes the change.
2398:        */
2399:       public void valueChanged(TreeSelectionEvent event)
2400:       {
2401:       }
2402:    }// TreeSelectionHandler
2403: 
2404:    /**
2405:     * For the first selected row expandedness will be toggled.
2406:     */
2407:    public class TreeToggleAction
2408:          extends AbstractAction
2409:    {
2410:       /**
2411:        * Constructor
2412:        * 
2413:        * @param name is the name of <code>Action</code> field
2414:        */
2415:       public TreeToggleAction(String name)
2416:       {
2417:       }
2418: 
2419:       /**
2420:        * Invoked when an action occurs.
2421:        * 
2422:        * @param e the event that occured
2423:        */
2424:       public void actionPerformed(ActionEvent e)
2425:       {
2426:       }
2427: 
2428:       /**
2429:        * Returns true if the action is enabled.
2430:        * 
2431:        * @return true if the action is enabled, false otherwise
2432:        */
2433:       public boolean isEnabled()
2434:       {
2435:          return false;
2436:       }
2437:    } // TreeToggleAction
2438: 
2439:    /**
2440:     * TreeTraverseAction is the action used for left/right keys. Will toggle
2441:     * the expandedness of a node, as well as potentially incrementing the
2442:     * selection.
2443:     */
2444:    public class TreeTraverseAction
2445:          extends AbstractAction
2446:    {
2447:       /**
2448:        * Determines direction to traverse, 1 means expand, -1 means collapse.
2449:        */
2450:       protected int direction;
2451: 
2452:       /**
2453:        * Constructor
2454:        * 
2455:        * @param direction to traverse
2456:        * @param name is the name of the direction
2457:        */
2458:       public TreeTraverseAction(int direction, String name)
2459:       {
2460:       }
2461: 
2462:       /**
2463:        * Invoked when an action occurs.
2464:        * 
2465:        * @param e the event that occured
2466:        */
2467:       public void actionPerformed(ActionEvent e)
2468:       {
2469:       }
2470: 
2471:       /**
2472:        * Returns true if the action is enabled.
2473:        * 
2474:        * @return true if the action is enabled, false otherwise
2475:        */
2476:       public boolean isEnabled()
2477:       {
2478:          return false;
2479:       }
2480:    } // TreeTraverseAction
2481: 
2482:    /* * HELPER METHODS FOR PAINTING * */
2483: 
2484:    /**
2485:     * Returns the cell bounds for painting selected cells
2486:     * 
2487:     * @param x is the x location of the cell
2488:     * @param y is the y location of the cell
2489:     * @param cell is the Object to get the bounds for
2490:     * 
2491:     * @returns Rectangle that represents the cell bounds
2492:     */
2493:    private Rectangle getCellBounds(int x, int y, Object cell)
2494:    {
2495:       if (cell != null)
2496:       {
2497:          String s = cell.toString();
2498:          Font f = tree.getFont();
2499:          FontMetrics fm = tree.getToolkit().getFontMetrics(tree.getFont());
2500:          
2501:          return new Rectangle(x, y, SwingUtilities.computeStringWidth(fm, s),
2502:                fm.getHeight());
2503:       }
2504:       return null;
2505:    }
2506: 
2507:    /**
2508:     * Paints a leaf in the tree
2509:     * 
2510:     * @param g the Graphics context in which to paint
2511:     * @param x the x location of the leaf
2512:     * @param y the y location of the leaf
2513:     * @param tree the tree to draw on
2514:     * @param leaf the object to draw
2515:     */
2516:    private void paintLeaf(Graphics g, int x, int y, JTree tree, Object leaf)
2517:    {
2518:       TreePath curr = new TreePath(((DefaultMutableTreeNode) leaf).getPath());
2519:       boolean selected = tree.isPathSelected(curr);
2520: 
2521:       if (tree.isVisible(curr))
2522:       {          
2523:          DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) 
2524:                                              tree.getCellRenderer();
2525:          boolean hasIcons = false;
2526:          Icon li = dtcr.getLeafIcon();
2527:          if (li != null)
2528:             hasIcons = true;
2529:          
2530:          if (selected)
2531:          {
2532:             Component c = dtcr.getTreeCellRendererComponent(tree, leaf,
2533:                   true, false, true, 0, false);
2534:             
2535:             if (hasIcons)
2536:             {
2537:                li.paintIcon(c, g, x, y + 2);
2538:                x += li.getIconWidth() + 4;
2539:             }
2540:             rendererPane.paintComponent(g, c, tree, 
2541:                                     getCellBounds(x, y, leaf));
2542:          }
2543:          else
2544:          {            
2545:             Component c = dtcr.getTreeCellRendererComponent(
2546:                   tree, leaf, false, false, true, 0, false);
2547:             
2548:             g.translate(x, y);
2549:             
2550:             if (hasIcons)
2551:             {
2552:                Component icon = dtcr.getTreeCellRendererComponent(tree, 
2553:                   li, false, false, true, 0, false); 
2554:                icon.paint(g);
2555:             }
2556:             
2557:             c.paint(g);
2558:             g.translate(-x, -y);
2559:          }
2560:       }
2561:    }
2562: 
2563:    /**
2564:     * Paints a non-leaf in the tree
2565:     * 
2566:     * @param g the Graphics context in which to paint
2567:     * @param x the x location of the non-leaf
2568:     * @param y the y location of the non-leaf
2569:     * @param tree the tree to draw on
2570:     * @param nonLeaf the object to draw
2571:     */
2572:    private void paintNonLeaf(Graphics g, int x, int y, JTree tree,
2573:          Object nonLeaf)
2574:    {
2575:       TreePath curr = new TreePath(((DefaultMutableTreeNode) nonLeaf).getPath());
2576:       boolean selected = tree.isPathSelected(curr);
2577:       boolean expanded = tree.isExpanded(curr);
2578: 
2579:       if (tree.isVisible(curr))
2580:       {
2581:             DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) 
2582:                                                 tree.getCellRenderer();
2583:             boolean hasIcons = false;
2584:             boolean hasOtherIcons = false;
2585:             Icon oi = dtcr.getOpenIcon();
2586:             Icon ci = dtcr.getClosedIcon();
2587:             
2588:             if (oi != null || ci != null)
2589:                hasIcons = true;
2590:             
2591:             if (selected)
2592:             {      
2593:                Component c = dtcr.getTreeCellRendererComponent(tree, nonLeaf,
2594:                      true, expanded, false, 0, false);
2595: 
2596:                if (hasIcons)
2597:                {
2598:                   if (expanded)
2599:                   {
2600:                      oi.paintIcon(c, g, x, y + 2);
2601:                      x += (oi.getIconWidth() + 4);
2602:                   }
2603:                   else
2604:                   {
2605:                      ci.paintIcon(c, g, x, y + 2);
2606:                      x += (ci.getIconWidth() + 4);
2607:                   }
2608:                   
2609:                }
2610:                rendererPane.paintComponent(g, c, tree, 
2611:                            getCellBounds(x, y, nonLeaf));
2612:             }
2613:             else
2614:             {
2615:                Component c = dtcr.getTreeCellRendererComponent(tree, nonLeaf, 
2616:                                           false, expanded, false, 0, false);
2617:                g.translate(x, y);
2618:                
2619:                if (hasIcons)
2620:                {
2621:                   Component icon;
2622:                   if (expanded)
2623:                      icon = dtcr.getTreeCellRendererComponent(tree, 
2624:                         oi, false, false, false, 0, false);
2625:                   else
2626:                      icon = dtcr.getTreeCellRendererComponent(tree, 
2627:                         ci, false, false, false, 0, false);
2628:                   
2629:                   icon.paint(g);
2630:                }
2631:                c.paint(g);
2632:                g.translate(-x, -y);
2633:             }
2634:       }
2635:    }
2636: 
2637:    /**
2638:     * Recursively paints all elements of the tree
2639:     * 
2640:     * @param g the Graphics context in which to paint
2641:     * @param indentation of the current object
2642:     * @param descent is the number of elements drawn
2643:     * @param childNumber is the index of the current child in the tree
2644:     * @param depth is the depth of the current object in the tree
2645:     * @param tree is the tree to draw to
2646:     * @param mod is the TreeModel we are using to draw
2647:     * @param curr is the current object to draw
2648:     * 
2649:     * @return int - current descent of the tree
2650:     */
2651:    private int paintRecursive(Graphics g, int indentation, int descent,
2652:          int childNumber, int depth, JTree tree, TreeModel mod, Object curr)
2653:    {
2654:       Rectangle clip = g.getClipBounds();
2655:       if (indentation > clip.x + clip.width + rightChildIndent
2656:             || descent > clip.y + clip.height + getRowHeight())
2657:          return descent;
2658: 
2659:       int halfHeight = getRowHeight() / 2;
2660:       int halfWidth = rightChildIndent / 2;
2661:       int y0 = descent + halfHeight;
2662:       int heightOfLine = descent + halfHeight;
2663:       
2664:       if (mod.isLeaf(curr))
2665:       {
2666:          paintLeaf(g, indentation + 4, descent, tree, curr);
2667:          descent += getRowHeight();
2668:       }
2669:       else
2670:       {
2671:          if (depth > 0 || tree.isRootVisible())
2672:          {
2673:             paintNonLeaf(g, indentation + 4, descent, tree, curr);
2674:             descent += getRowHeight();
2675:             y0 += halfHeight;
2676:          }
2677:          
2678:          int max = mod.getChildCount(curr);
2679:          if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) curr)
2680:                .getPath())))
2681:          {
2682:             for (int i = 0; i < max; ++i)
2683:             {
2684:                g.setColor(getHashColor());
2685:                heightOfLine = descent + halfHeight;
2686:                g.drawLine(indentation + halfWidth, heightOfLine,
2687:                      indentation + rightChildIndent, heightOfLine);
2688:                               
2689:                descent = paintRecursive(g, indentation + rightChildIndent,
2690:                      descent, i, depth + 1, tree, mod, mod.getChild(curr, i));
2691:             }
2692:          }
2693:       }
2694: 
2695:       if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) curr)
2696:             .getPath())))
2697:          if (y0 != heightOfLine)
2698:          {
2699:             g.setColor(getHashColor());
2700:             g.drawLine(indentation + halfWidth, y0, indentation + halfWidth,
2701:                   heightOfLine);
2702:          }
2703:       
2704:       return descent;
2705:    }
2706:    
2707:    /**
2708:     * Recursively paints all the control icons on the tree.
2709:     * 
2710:     * @param g the Graphics context in which to paint
2711:     * @param indentation of the current object
2712:     * @param descent is the number of elements drawn
2713:     * @param childNumber is the index of the current child in the tree
2714:     * @param depth is the depth of the current object in the tree
2715:     * @param tree is the tree to draw to
2716:     * @param mod is the TreeModel we are using to draw
2717:     * @param curr is the current object to draw
2718:     * 
2719:     * @return int - current descent of the tree
2720:     */
2721:    private int paintControlIcons(Graphics g, int indentation, int descent,
2722:          int childNumber, int depth, JTree tree, TreeModel mod, Object node)
2723:    {
2724:       int h = descent;
2725:       int rowHeight = getRowHeight();
2726:       Icon ei = UIManager.getLookAndFeelDefaults().
2727:          getIcon("Tree.expandedIcon");
2728:       Icon ci = UIManager.getLookAndFeelDefaults().
2729:          getIcon("Tree.collapsedIcon");
2730:       Rectangle clip = g.getClipBounds();
2731:       if (ci == null || ei == null || indentation > clip.x + clip.width +
2732:             rightChildIndent || descent > clip.y + clip.height + 
2733:                getRowHeight())
2734:          return descent;
2735:       
2736:       if (mod.isLeaf(node))
2737:       {
2738:          descent += rowHeight;
2739:       }
2740:       else 
2741:       {
2742:          if (depth > 0 || tree.isRootVisible())
2743:          {
2744:             descent += rowHeight;
2745:          }
2746:          
2747:          int max = mod.getChildCount(node);
2748:          if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) node)
2749:                .getPath())))
2750:          {
2751:             if (!node.equals(mod.getRoot()))
2752:                ei.paintIcon(tree, g, indentation - rightChildIndent - 3, h);
2753:             
2754:             for (int i = 0; i < max; ++i)
2755:             {           
2756:                descent = paintControlIcons(g, indentation + rightChildIndent,
2757:                      descent, i, depth + 1, tree, mod, mod.getChild(node, i));
2758:             }
2759:          }
2760:          else if (!node.equals(mod.getRoot()))
2761:             ci.paintIcon(tree, g, indentation - rightChildIndent - 3, 
2762:                   descent - getRowHeight());
2763:       }
2764:       
2765:       return descent;
2766:    }
2767: } // BasicTreeU