KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicTreeUI


1 /*
2  * @(#)BasicTreeUI.java 1.178 06/04/18
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import javax.swing.*;
11 import javax.swing.event.*;
12 import java.awt.*;
13 import java.awt.event.*;
14 import java.awt.datatransfer.*;
15 import java.awt.dnd.*;
16 import java.beans.*;
17 import java.io.*;
18 import java.util.Enumeration JavaDoc;
19 import java.util.Hashtable JavaDoc;
20 import java.util.TooManyListenersException JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.Comparator JavaDoc;
24 import javax.swing.plaf.ActionMapUIResource JavaDoc;
25 import javax.swing.plaf.ComponentUI JavaDoc;
26 import javax.swing.plaf.UIResource JavaDoc;
27 import javax.swing.plaf.TreeUI JavaDoc;
28 import javax.swing.tree.*;
29 import javax.swing.text.Position JavaDoc;
30 import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag JavaDoc;
31 import com.sun.java.swing.SwingUtilities2;
32 import static com.sun.java.swing.SwingUtilities2.DRAG_FIX;
33
34 import sun.swing.DefaultLookup;
35 import sun.swing.UIAction;
36
37 /**
38  * The basic L&F for a hierarchical data structure.
39  * <p>
40  *
41  * @version 1.178 04/18/06
42  * @author Scott Violet
43  * @author Shannon Hickey (improved drag recognition)
44  */

45
46 public class BasicTreeUI extends TreeUI JavaDoc
47 {
48     // Old actions forward to an instance of this.
49
static private final Actions SHARED_ACTION = new Actions();
50
51     static private final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0);
52
53     transient protected Icon collapsedIcon;
54     transient protected Icon expandedIcon;
55
56     /**
57       * Color used to draw hash marks. If <code>null</code> no hash marks
58       * will be drawn.
59       */

60     private Color hashColor;
61
62     /** Distance between left margin and where vertical dashes will be
63       * drawn. */

64     protected int leftChildIndent;
65     /** Distance to add to leftChildIndent to determine where cell
66       * contents will be drawn. */

67     protected int rightChildIndent;
68     /** Total distance that will be indented. The sum of leftChildIndent
69       * and rightChildIndent. */

70     protected int totalChildIndent;
71
72     /** Minimum preferred size. */
73     protected Dimension preferredMinSize;
74
75     /** Index of the row that was last selected. */
76     protected int lastSelectedRow;
77
78     /** Component that we're going to be drawing into. */
79     protected JTree tree;
80
81     /** Renderer that is being used to do the actual cell drawing. */
82     transient protected TreeCellRenderer currentCellRenderer;
83
84     /** Set to true if the renderer that is currently in the tree was
85      * created by this instance. */

86     protected boolean createdRenderer;
87
88     /** Editor for the tree. */
89     transient protected TreeCellEditor cellEditor;
90
91     /** Set to true if editor that is currently in the tree was
92      * created by this instance. */

93     protected boolean createdCellEditor;
94
95     /** Set to false when editing and shouldSelectCell() returns true meaning
96       * the node should be selected before editing, used in completeEditing. */

97     protected boolean stopEditingInCompleteEditing;
98
99     /** Used to paint the TreeCellRenderer. */
100     protected CellRendererPane rendererPane;
101
102     /** Size needed to completely display all the nodes. */
103     protected Dimension preferredSize;
104
105     /** Is the preferredSize valid? */
106     protected boolean validCachedPreferredSize;
107
108     /** Object responsible for handling sizing and expanded issues. */
109     protected AbstractLayoutCache treeState;
110
111
112     /** Used for minimizing the drawing of vertical lines. */
113     protected Hashtable JavaDoc<TreePath,Boolean JavaDoc> drawingCache;
114
115     /** True if doing optimizations for a largeModel. Subclasses that
116      * don't support this may wish to override createLayoutCache to not
117      * return a FixedHeightLayoutCache instance. */

118     protected boolean largeModel;
119
120     /** Reponsible for telling the TreeState the size needed for a node. */
121     protected AbstractLayoutCache.NodeDimensions nodeDimensions;
122
123     /** Used to determine what to display. */
124     protected TreeModel treeModel;
125
126     /** Model maintaing the selection. */
127     protected TreeSelectionModel treeSelectionModel;
128
129     /** How much the depth should be offset to properly calculate
130      * x locations. This is based on whether or not the root is visible,
131      * and if the root handles are visible. */

132     protected int depthOffset;
133
134     /** Last width the tree was at when painted. This is used when
135      * !leftToRigth to notice the bounds have changed so that we can instruct
136      * the TreeState to relayout. */

137     private int lastWidth;
138
139     // Following 4 ivars are only valid when editing.
140

141     /** When editing, this will be the Component that is doing the actual
142       * editing. */

143     protected Component editingComponent;
144
145     /** Path that is being edited. */
146     protected TreePath editingPath;
147
148     /** Row that is being edited. Should only be referenced if
149      * editingComponent is not null. */

150     protected int editingRow;
151
152     /** Set to true if the editor has a different size than the renderer. */
153     protected boolean editorHasDifferentSize;
154
155     /** Row correspondin to lead path. */
156     private int leadRow;
157     /** If true, the property change event for LEAD_SELECTION_PATH_PROPERTY,
158      * or ANCHOR_SELECTION_PATH_PROPERTY will not generate a repaint. */

159     private boolean ignoreLAChange;
160
161     /** Indicates the orientation. */
162     private boolean leftToRight;
163
164     // Cached listeners
165
private PropertyChangeListener propertyChangeListener;
166     private PropertyChangeListener selectionModelPropertyChangeListener;
167     private MouseListener mouseListener;
168     private FocusListener focusListener;
169     private KeyListener keyListener;
170     /** Used for large models, listens for moved/resized events and
171      * updates the validCachedPreferredSize bit accordingly. */

172     private ComponentListener componentListener;
173     /** Listens for CellEditor events. */
174     private CellEditorListener cellEditorListener;
175     /** Updates the display when the selection changes. */
176     private TreeSelectionListener treeSelectionListener;
177     /** Is responsible for updating the display based on model events. */
178     private TreeModelListener treeModelListener;
179     /** Updates the treestate as the nodes expand. */
180     private TreeExpansionListener treeExpansionListener;
181
182     /** UI property indicating whether to paint lines */
183     private boolean paintLines = true;
184
185     /** UI property for painting dashed lines */
186     private boolean lineTypeDashed;
187
188     /**
189      * The time factor to treate the series of typed alphanumeric key
190      * as prefix for first letter navigation.
191      */

192     private long timeFactor = 1000L;
193
194     private Handler handler;
195
196     /**
197      * A temporary variable for communication between startEditingOnRelease
198      * and startEditing.
199      */

200     private MouseEvent releaseEvent;
201
202     public static ComponentUI JavaDoc createUI(JComponent x) {
203     return new BasicTreeUI JavaDoc();
204     }
205
206
207     static void loadActionMap(LazyActionMap JavaDoc map) {
208     map.put(new Actions(Actions.SELECT_PREVIOUS));
209         map.put(new Actions(Actions.SELECT_PREVIOUS_CHANGE_LEAD));
210     map.put(new Actions(Actions.SELECT_PREVIOUS_EXTEND_SELECTION));
211
212     map.put(new Actions(Actions.SELECT_NEXT));
213     map.put(new Actions(Actions.SELECT_NEXT_CHANGE_LEAD));
214     map.put(new Actions(Actions.SELECT_NEXT_EXTEND_SELECTION));
215
216     map.put(new Actions(Actions.SELECT_CHILD));
217     map.put(new Actions(Actions.SELECT_CHILD_CHANGE_LEAD));
218
219     map.put(new Actions(Actions.SELECT_PARENT));
220     map.put(new Actions(Actions.SELECT_PARENT_CHANGE_LEAD));
221
222     map.put(new Actions(Actions.SCROLL_UP_CHANGE_SELECTION));
223     map.put(new Actions(Actions.SCROLL_UP_CHANGE_LEAD));
224     map.put(new Actions(Actions.SCROLL_UP_EXTEND_SELECTION));
225
226     map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_SELECTION));
227     map.put(new Actions(Actions.SCROLL_DOWN_EXTEND_SELECTION));
228     map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_LEAD));
229
230     map.put(new Actions(Actions.SELECT_FIRST));
231     map.put(new Actions(Actions.SELECT_FIRST_CHANGE_LEAD));
232     map.put(new Actions(Actions.SELECT_FIRST_EXTEND_SELECTION));
233
234     map.put(new Actions(Actions.SELECT_LAST));
235     map.put(new Actions(Actions.SELECT_LAST_CHANGE_LEAD));
236     map.put(new Actions(Actions.SELECT_LAST_EXTEND_SELECTION));
237
238     map.put(new Actions(Actions.TOGGLE));
239
240     map.put(new Actions(Actions.CANCEL_EDITING));
241
242     map.put(new Actions(Actions.START_EDITING));
243
244     map.put(new Actions(Actions.SELECT_ALL));
245
246     map.put(new Actions(Actions.CLEAR_SELECTION));
247
248     map.put(new Actions(Actions.SCROLL_LEFT));
249     map.put(new Actions(Actions.SCROLL_RIGHT));
250
251     map.put(new Actions(Actions.SCROLL_LEFT_EXTEND_SELECTION));
252     map.put(new Actions(Actions.SCROLL_RIGHT_EXTEND_SELECTION));
253
254     map.put(new Actions(Actions.SCROLL_RIGHT_CHANGE_LEAD));
255     map.put(new Actions(Actions.SCROLL_LEFT_CHANGE_LEAD));
256
257         map.put(new Actions(Actions.EXPAND));
258         map.put(new Actions(Actions.COLLAPSE));
259         map.put(new Actions(Actions.MOVE_SELECTION_TO_PARENT));
260
261         map.put(new Actions(Actions.ADD_TO_SELECTION));
262         map.put(new Actions(Actions.TOGGLE_AND_ANCHOR));
263         map.put(new Actions(Actions.EXTEND_TO));
264         map.put(new Actions(Actions.MOVE_SELECTION_TO));
265
266         map.put(TransferHandler.getCutAction());
267         map.put(TransferHandler.getCopyAction());
268         map.put(TransferHandler.getPasteAction());
269     }
270
271
272     public BasicTreeUI() {
273     super();
274     }
275
276     protected Color getHashColor() {
277         return hashColor;
278     }
279
280     protected void setHashColor(Color color) {
281         hashColor = color;
282     }
283
284     public void setLeftChildIndent(int newAmount) {
285     leftChildIndent = newAmount;
286     totalChildIndent = leftChildIndent + rightChildIndent;
287     if(treeState != null)
288         treeState.invalidateSizes();
289     updateSize();
290     }
291
292     public int getLeftChildIndent() {
293     return leftChildIndent;
294     }
295
296     public void setRightChildIndent(int newAmount) {
297     rightChildIndent = newAmount;
298     totalChildIndent = leftChildIndent + rightChildIndent;
299     if(treeState != null)
300         treeState.invalidateSizes();
301     updateSize();
302     }
303
304     public int getRightChildIndent() {
305     return rightChildIndent;
306     }
307
308     public void setExpandedIcon(Icon newG) {
309     expandedIcon = newG;
310     }
311
312     public Icon getExpandedIcon() {
313     return expandedIcon;
314     }
315
316     public void setCollapsedIcon(Icon newG) {
317     collapsedIcon = newG;
318     }
319
320     public Icon getCollapsedIcon() {
321     return collapsedIcon;
322     }
323
324     //
325
// Methods for configuring the behavior of the tree. None of them
326
// push the value to the JTree instance. You should really only
327
// call these methods on the JTree.
328
//
329

330     /**
331      * Updates the componentListener, if necessary.
332      */

333     protected void setLargeModel(boolean largeModel) {
334     if(getRowHeight() < 1)
335         largeModel = false;
336     if(this.largeModel != largeModel) {
337         completeEditing();
338         this.largeModel = largeModel;
339         treeState = createLayoutCache();
340         configureLayoutCache();
341         updateLayoutCacheExpandedNodes();
342         updateSize();
343     }
344     }
345
346     protected boolean isLargeModel() {
347     return largeModel;
348     }
349
350     /**
351      * Sets the row height, this is forwarded to the treeState.
352      */

353     protected void setRowHeight(int rowHeight) {
354     completeEditing();
355     if(treeState != null) {
356         setLargeModel(tree.isLargeModel());
357         treeState.setRowHeight(rowHeight);
358         updateSize();
359     }
360     }
361
362     protected int getRowHeight() {
363     return (tree == null) ? -1 : tree.getRowHeight();
364     }
365
366     /**
367      * Sets the TreeCellRenderer to <code>tcr</code>. This invokes
368      * <code>updateRenderer</code>.
369      */

370     protected void setCellRenderer(TreeCellRenderer tcr) {
371     completeEditing();
372     updateRenderer();
373     if(treeState != null) {
374         treeState.invalidateSizes();
375         updateSize();
376     }
377     }
378
379     /**
380      * Return currentCellRenderer, which will either be the trees
381      * renderer, or defaultCellRenderer, which ever wasn't null.
382      */

383     protected TreeCellRenderer getCellRenderer() {
384     return currentCellRenderer;
385     }
386
387     /**
388      * Sets the TreeModel.
389      */

390     protected void setModel(TreeModel model) {
391     completeEditing();
392     if(treeModel != null && treeModelListener != null)
393         treeModel.removeTreeModelListener(treeModelListener);
394     treeModel = model;
395     if(treeModel != null) {
396         if(treeModelListener != null)
397         treeModel.addTreeModelListener(treeModelListener);
398     }
399     if(treeState != null) {
400         treeState.setModel(model);
401         updateLayoutCacheExpandedNodes();
402         updateSize();
403     }
404     }
405
406     protected TreeModel getModel() {
407     return treeModel;
408     }
409
410     /**
411      * Sets the root to being visible.
412      */

413     protected void setRootVisible(boolean newValue) {
414     completeEditing();
415     updateDepthOffset();
416     if(treeState != null) {
417         treeState.setRootVisible(newValue);
418         treeState.invalidateSizes();
419         updateSize();
420     }
421     }
422
423     protected boolean isRootVisible() {
424     return (tree != null) ? tree.isRootVisible() : false;
425     }
426
427     /**
428      * Determines whether the node handles are to be displayed.
429      */

430     protected void setShowsRootHandles(boolean newValue) {
431     completeEditing();
432     updateDepthOffset();
433     if(treeState != null) {
434         treeState.invalidateSizes();
435         updateSize();
436     }
437     }
438
439     protected boolean getShowsRootHandles() {
440     return (tree != null) ? tree.getShowsRootHandles() : false;
441     }
442
443     /**
444      * Sets the cell editor.
445      */

446     protected void setCellEditor(TreeCellEditor editor) {
447     updateCellEditor();
448     }
449
450     protected TreeCellEditor getCellEditor() {
451     return (tree != null) ? tree.getCellEditor() : null;
452     }
453
454     /**
455      * Configures the receiver to allow, or not allow, editing.
456      */

457     protected void setEditable(boolean newValue) {
458     updateCellEditor();
459     }
460
461     protected boolean isEditable() {
462     return (tree != null) ? tree.isEditable() : false;
463     }
464
465     /**
466      * Resets the selection model. The appropriate listener are installed
467      * on the model.
468      */

469     protected void setSelectionModel(TreeSelectionModel newLSM) {
470     completeEditing();
471     if(selectionModelPropertyChangeListener != null &&
472        treeSelectionModel != null)
473         treeSelectionModel.removePropertyChangeListener
474                       (selectionModelPropertyChangeListener);
475     if(treeSelectionListener != null && treeSelectionModel != null)
476         treeSelectionModel.removeTreeSelectionListener
477                        (treeSelectionListener);
478     treeSelectionModel = newLSM;
479     if(treeSelectionModel != null) {
480         if(selectionModelPropertyChangeListener != null)
481         treeSelectionModel.addPropertyChangeListener
482                       (selectionModelPropertyChangeListener);
483         if(treeSelectionListener != null)
484         treeSelectionModel.addTreeSelectionListener
485                            (treeSelectionListener);
486         if(treeState != null)
487         treeState.setSelectionModel(treeSelectionModel);
488     }
489     else if(treeState != null)
490         treeState.setSelectionModel(null);
491     if(tree != null)
492         tree.repaint();
493     }
494
495     protected TreeSelectionModel getSelectionModel() {
496     return treeSelectionModel;
497     }
498
499     //
500
// TreeUI methods
501
//
502

503     /**
504       * Returns the Rectangle enclosing the label portion that the
505       * last item in path will be drawn into. Will return null if
506       * any component in path is currently valid.
507       */

508     public Rectangle getPathBounds(JTree tree, TreePath path) {
509     if(tree != null && treeState != null) {
510         Insets i = tree.getInsets();
511         Rectangle bounds = treeState.getBounds(path, null);
512
513         if(bounds != null && i != null) {
514         bounds.x += i.left;
515         bounds.y += i.top;
516         }
517         return bounds;
518     }
519     return null;
520     }
521
522     /**
523       * Returns the path for passed in row. If row is not visible
524       * null is returned.
525       */

526     public TreePath getPathForRow(JTree tree, int row) {
527     return (treeState != null) ? treeState.getPathForRow(row) : null;
528     }
529
530     /**
531       * Returns the row that the last item identified in path is visible
532       * at. Will return -1 if any of the elements in path are not
533       * currently visible.
534       */

535     public int getRowForPath(JTree tree, TreePath path) {
536     return (treeState != null) ? treeState.getRowForPath(path) : -1;
537     }
538
539     /**
540       * Returns the number of rows that are being displayed.
541       */

542     public int getRowCount(JTree tree) {
543     return (treeState != null) ? treeState.getRowCount() : 0;
544     }
545
546     /**
547       * Returns the path to the node that is closest to x,y. If
548       * there is nothing currently visible this will return null, otherwise
549       * it'll always return a valid path. If you need to test if the
550       * returned object is exactly at x, y you should get the bounds for
551       * the returned path and test x, y against that.
552       */

553     public TreePath getClosestPathForLocation(JTree tree, int x, int y) {
554     if(tree != null && treeState != null) {
555         Insets i = tree.getInsets();
556
557         if(i == null)
558         i = EMPTY_INSETS;
559
560         return treeState.getPathClosestTo(x - i.left, y - i.top);
561     }
562     return null;
563     }
564
565     /**
566       * Returns true if the tree is being edited. The item that is being
567       * edited can be returned by getEditingPath().
568       */

569     public boolean isEditing(JTree tree) {
570     return (editingComponent != null);
571     }
572
573     /**
574       * Stops the current editing session. This has no effect if the
575       * tree isn't being edited. Returns true if the editor allows the
576       * editing session to stop.
577       */

578     public boolean stopEditing(JTree tree) {
579     if(editingComponent != null && cellEditor.stopCellEditing()) {
580         completeEditing(false, false, true);
581         return true;
582     }
583     return false;
584     }
585
586     /**
587       * Cancels the current editing session.
588       */

589     public void cancelEditing(JTree tree) {
590     if(editingComponent != null) {
591         completeEditing(false, true, false);
592     }
593     }
594
595     /**
596       * Selects the last item in path and tries to edit it. Editing will
597       * fail if the CellEditor won't allow it for the selected item.
598       */

599     public void startEditingAtPath(JTree tree, TreePath path) {
600     tree.scrollPathToVisible(path);
601     if(path != null && tree.isVisible(path))
602         startEditing(path, null);
603     }
604
605     /**
606      * Returns the path to the element that is being edited.
607      */

608     public TreePath getEditingPath(JTree tree) {
609     return editingPath;
610     }
611
612     //
613
// Install methods
614
//
615

616     public void installUI(JComponent c) {
617         if ( c == null ) {
618         throw new NullPointerException JavaDoc( "null component passed to BasicTreeUI.installUI()" );
619         }
620
621     tree = (JTree)c;
622
623     prepareForUIInstall();
624
625     // Boilerplate install block
626
installDefaults();
627     installKeyboardActions();
628     installComponents();
629     installListeners();
630
631     completeUIInstall();
632     }
633
634     /**
635      * Invoked after the <code>tree</code> instance variable has been
636      * set, but before any defaults/listeners have been installed.
637      */

638     protected void prepareForUIInstall() {
639     drawingCache = new Hashtable JavaDoc<TreePath,Boolean JavaDoc>(7);
640
641     // Data member initializations
642
leftToRight = BasicGraphicsUtils.isLeftToRight(tree);
643     lastWidth = tree.getWidth();
644     stopEditingInCompleteEditing = true;
645     lastSelectedRow = -1;
646     leadRow = -1;
647     preferredSize = new Dimension();
648
649     largeModel = tree.isLargeModel();
650     if(getRowHeight() <= 0)
651         largeModel = false;
652     setModel(tree.getModel());
653     }
654
655     /**
656      * Invoked from installUI after all the defaults/listeners have been
657      * installed.
658      */

659     protected void completeUIInstall() {
660     // Custom install code
661

662     this.setShowsRootHandles(tree.getShowsRootHandles());
663
664     updateRenderer();
665
666     updateDepthOffset();
667
668     setSelectionModel(tree.getSelectionModel());
669
670     // Create, if necessary, the TreeState instance.
671
treeState = createLayoutCache();
672     configureLayoutCache();
673
674     updateSize();
675     }
676
677     protected void installDefaults() {
678     if(tree.getBackground() == null ||
679        tree.getBackground() instanceof UIResource JavaDoc) {
680         tree.setBackground(UIManager.getColor("Tree.background"));
681     }
682     if(getHashColor() == null || getHashColor() instanceof UIResource JavaDoc) {
683         setHashColor(UIManager.getColor("Tree.hash"));
684     }
685     if (tree.getFont() == null || tree.getFont() instanceof UIResource JavaDoc)
686         tree.setFont( UIManager.getFont("Tree.font") );
687         // JTree's original row height is 16. To correctly display the
688
// contents on Linux we should have set it to 18, Windows 19 and
689
// Solaris 20. As these values vary so much it's too hard to
690
// be backward compatable and try to update the row height, we're
691
// therefor NOT going to adjust the row height based on font. If the
692
// developer changes the font, it's there responsibility to update
693
// the row height.
694

695     setExpandedIcon( (Icon)UIManager.get( "Tree.expandedIcon" ) );
696     setCollapsedIcon( (Icon)UIManager.get( "Tree.collapsedIcon" ) );
697
698     setLeftChildIndent(((Integer JavaDoc)UIManager.get("Tree.leftChildIndent")).
699                intValue());
700     setRightChildIndent(((Integer JavaDoc)UIManager.get("Tree.rightChildIndent")).
701                intValue());
702
703     LookAndFeel.installProperty(tree, "rowHeight",
704                     UIManager.get("Tree.rowHeight"));
705
706         largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0);
707
708     Object JavaDoc scrollsOnExpand = UIManager.get("Tree.scrollsOnExpand");
709     if (scrollsOnExpand != null) {
710         LookAndFeel.installProperty(tree, "scrollsOnExpand", scrollsOnExpand);
711     }
712
713     paintLines = UIManager.getBoolean("Tree.paintLines");
714     lineTypeDashed = UIManager.getBoolean("Tree.lineTypeDashed");
715     
716     Long JavaDoc l = (Long JavaDoc)UIManager.get("Tree.timeFactor");
717     timeFactor = (l!=null) ? l.longValue() : 1000L;
718         
719         Object JavaDoc showsRootHandles = UIManager.get("Tree.showsRootHandles");
720         if (showsRootHandles != null) {
721             LookAndFeel.installProperty(tree,
722                     JTree.SHOWS_ROOT_HANDLES_PROPERTY, showsRootHandles);
723         }
724     }
725
726     protected void installListeners() {
727         if ( (propertyChangeListener = createPropertyChangeListener())
728          != null ) {
729         tree.addPropertyChangeListener(propertyChangeListener);
730     }
731         if (!DRAG_FIX) {
732             tree.addMouseListener(defaultDragRecognizer);
733             tree.addMouseMotionListener(defaultDragRecognizer);
734         }
735         if ( (mouseListener = createMouseListener()) != null ) {
736         tree.addMouseListener(mouseListener);
737         if (mouseListener instanceof MouseMotionListener) {
738         tree.addMouseMotionListener((MouseMotionListener)mouseListener);
739         }
740     }
741         if ((focusListener = createFocusListener()) != null ) {
742         tree.addFocusListener(focusListener);
743     }
744         if ((keyListener = createKeyListener()) != null) {
745         tree.addKeyListener(keyListener);
746     }
747     if((treeExpansionListener = createTreeExpansionListener()) != null) {
748         tree.addTreeExpansionListener(treeExpansionListener);
749     }
750     if((treeModelListener = createTreeModelListener()) != null &&
751        treeModel != null) {
752         treeModel.addTreeModelListener(treeModelListener);
753     }
754     if((selectionModelPropertyChangeListener =
755         createSelectionModelPropertyChangeListener()) != null &&
756        treeSelectionModel != null) {
757         treeSelectionModel.addPropertyChangeListener
758         (selectionModelPropertyChangeListener);
759     }
760     if((treeSelectionListener = createTreeSelectionListener()) != null &&
761        treeSelectionModel != null) {
762         treeSelectionModel.addTreeSelectionListener(treeSelectionListener);
763     }
764
765     TransferHandler th = tree.getTransferHandler();
766     if (th == null || th instanceof UIResource JavaDoc) {
767         tree.setTransferHandler(defaultTransferHandler);
768     }
769     DropTarget dropTarget = tree.getDropTarget();
770     if (dropTarget instanceof UIResource JavaDoc) {
771             if (defaultDropTargetListener == null) {
772                 defaultDropTargetListener = new TreeDropTargetListener();
773             }
774         try {
775         dropTarget.addDropTargetListener(defaultDropTargetListener);
776         } catch (TooManyListenersException JavaDoc tmle) {
777         // should not happen... swing drop target is multicast
778
}
779     }
780         LookAndFeel.installProperty(tree, "opaque", Boolean.TRUE);
781     }
782
783     protected void installKeyboardActions() {
784     InputMap km = getInputMap(JComponent.
785                   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
786
787     SwingUtilities.replaceUIInputMap(tree, JComponent.
788                      WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
789                      km);
790     km = getInputMap(JComponent.WHEN_FOCUSED);
791     SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED, km);
792
793         LazyActionMap.installLazyActionMap(tree, BasicTreeUI JavaDoc.class,
794                                            "Tree.actionMap");
795     }
796
797     InputMap getInputMap(int condition) {
798     if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
799         return (InputMap)DefaultLookup.get(tree, this,
800                                                "Tree.ancestorInputMap");
801     }
802     else if (condition == JComponent.WHEN_FOCUSED) {
803         InputMap keyMap = (InputMap)DefaultLookup.get(tree, this,
804                                                       "Tree.focusInputMap");
805         InputMap rtlKeyMap;
806
807         if (tree.getComponentOrientation().isLeftToRight() ||
808           ((rtlKeyMap = (InputMap)DefaultLookup.get(tree, this,
809                   "Tree.focusInputMap.RightToLeft")) == null)) {
810         return keyMap;
811         } else {
812         rtlKeyMap.setParent(keyMap);
813         return rtlKeyMap;
814         }
815     }
816     return null;
817     }
818
819     /**
820      * Intalls the subcomponents of the tree, which is the renderer pane.
821      */

822     protected void installComponents() {
823     if ((rendererPane = createCellRendererPane()) != null) {
824         tree.add( rendererPane );
825     }
826     }
827
828     //
829
// Create methods.
830
//
831

832     /**
833      * Creates an instance of NodeDimensions that is able to determine
834      * the size of a given node in the tree.
835      */

836     protected AbstractLayoutCache.NodeDimensions createNodeDimensions() {
837     return new NodeDimensionsHandler();
838     }
839
840     /**
841      * Creates a listener that is responsible that updates the UI based on
842      * how the tree changes.
843      */

844     protected PropertyChangeListener createPropertyChangeListener() {
845         return getHandler();
846     }
847
848     private Handler getHandler() {
849         if (handler == null) {
850             handler = DRAG_FIX ? new DragFixHandler() : new Handler();
851         }
852         return handler;
853     }
854
855     /**
856      * Creates the listener responsible for updating the selection based on
857      * mouse events.
858      */

859     protected MouseListener createMouseListener() {
860         return getHandler();
861     }
862
863     /**
864      * Creates a listener that is responsible for updating the display
865      * when focus is lost/gained.
866      */

867     protected FocusListener createFocusListener() {
868         return getHandler();
869     }
870
871     /**
872      * Creates the listener reponsible for getting key events from
873      * the tree.
874      */

875     protected KeyListener createKeyListener() {
876         return getHandler();
877     }
878
879     /**
880      * Creates the listener responsible for getting property change
881      * events from the selection model.
882      */

883     protected PropertyChangeListener createSelectionModelPropertyChangeListener() {
884     return getHandler();
885     }
886
887     /**
888      * Creates the listener that updates the display based on selection change
889      * methods.
890      */

891     protected TreeSelectionListener createTreeSelectionListener() {
892     return getHandler();
893     }
894
895     /**
896      * Creates a listener to handle events from the current editor.
897      */

898     protected CellEditorListener createCellEditorListener() {
899     return getHandler();
900     }
901
902     /**
903      * Creates and returns a new ComponentHandler. This is used for
904      * the large model to mark the validCachedPreferredSize as invalid
905      * when the component moves.
906      */

907     protected ComponentListener createComponentListener() {
908     return new ComponentHandler();
909     }
910
911     /**
912      * Creates and returns the object responsible for updating the treestate
913      * when nodes expanded state changes.
914      */

915     protected TreeExpansionListener createTreeExpansionListener() {
916     return getHandler();
917     }
918
919     /**
920      * Creates the object responsible for managing what is expanded, as
921      * well as the size of nodes.
922      */

923     protected AbstractLayoutCache createLayoutCache() {
924     if(isLargeModel() && getRowHeight() > 0) {
925         return new FixedHeightLayoutCache();
926     }
927     return new VariableHeightLayoutCache();
928     }
929
930     /**
931      * Returns the renderer pane that renderer components are placed in.
932      */

933     protected CellRendererPane createCellRendererPane() {
934         return new CellRendererPane();
935     }
936
937     /**
938       * Creates a default cell editor.
939       */

940     protected TreeCellEditor createDefaultCellEditor() {
941     if(currentCellRenderer != null &&
942        (currentCellRenderer instanceof DefaultTreeCellRenderer)) {
943         DefaultTreeCellEditor editor = new DefaultTreeCellEditor
944                 (tree, (DefaultTreeCellRenderer)currentCellRenderer);
945
946         return editor;
947     }
948     return new DefaultTreeCellEditor(tree, null);
949     }
950
951     /**
952       * Returns the default cell renderer that is used to do the
953       * stamping of each node.
954       */

955     protected TreeCellRenderer createDefaultCellRenderer() {
956     return new DefaultTreeCellRenderer();
957     }
958
959     /**
960      * Returns a listener that can update the tree when the model changes.
961      */

962     protected TreeModelListener createTreeModelListener() {
963     return getHandler();
964     }
965
966     //
967
// Uninstall methods
968
//
969

970     public void uninstallUI(JComponent c) {
971     completeEditing();
972
973     prepareForUIUninstall();
974
975     uninstallDefaults();
976     uninstallListeners();
977     uninstallKeyboardActions();
978     uninstallComponents();
979
980     completeUIUninstall();
981     }
982
983     protected void prepareForUIUninstall() {
984     }
985
986     protected void completeUIUninstall() {
987     if(createdRenderer) {
988         tree.setCellRenderer(null);
989     }
990     if(createdCellEditor) {
991         tree.setCellEditor(null);
992     }
993     cellEditor = null;
994     currentCellRenderer = null;
995     rendererPane = null;
996         componentListener = null;
997     propertyChangeListener = null;
998     mouseListener = null;
999     focusListener = null;
1000    keyListener = null;
1001    setSelectionModel(null);
1002    treeState = null;
1003    drawingCache = null;
1004    selectionModelPropertyChangeListener = null;
1005    tree = null;
1006    treeModel = null;
1007    treeSelectionModel = null;
1008    treeSelectionListener = null;
1009    treeExpansionListener = null;
1010    }
1011
1012    protected void uninstallDefaults() {
1013    if (tree.getTransferHandler() instanceof UIResource JavaDoc) {
1014        tree.setTransferHandler(null);
1015    }
1016    }
1017
1018    protected void uninstallListeners() {
1019    if(componentListener != null) {
1020        tree.removeComponentListener(componentListener);
1021    }
1022        if (propertyChangeListener != null) {
1023        tree.removePropertyChangeListener(propertyChangeListener);
1024    }
1025        if (!DRAG_FIX) {
1026            tree.removeMouseListener(defaultDragRecognizer);
1027            tree.removeMouseMotionListener(defaultDragRecognizer);
1028        }
1029        if (mouseListener != null) {
1030        tree.removeMouseListener(mouseListener);
1031        if (mouseListener instanceof MouseMotionListener) {
1032        tree.removeMouseMotionListener((MouseMotionListener)mouseListener);
1033        }
1034    }
1035        if (focusListener != null) {
1036        tree.removeFocusListener(focusListener);
1037    }
1038        if (keyListener != null) {
1039        tree.removeKeyListener(keyListener);
1040    }
1041    if(treeExpansionListener != null) {
1042        tree.removeTreeExpansionListener(treeExpansionListener);
1043    }
1044    if(treeModel != null && treeModelListener !=