GNU Classpath (0.17) | ||
Frames | No Frames |
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
GNU Classpath (0.17) |