jdk/src/share/classes/javax/swing/plaf/basic/BasicTreeUI.java
changeset 25775 6a6fd62bc6d5
parent 25565 ce603b34c98d
child 25784 656f7d3eef5f
equal deleted inserted replaced
25774:21b78da4b2df 25775:6a6fd62bc6d5
    61         new StringBuilder("Tree.baselineComponent");
    61         new StringBuilder("Tree.baselineComponent");
    62 
    62 
    63     // Old actions forward to an instance of this.
    63     // Old actions forward to an instance of this.
    64     static private final Actions SHARED_ACTION = new Actions();
    64     static private final Actions SHARED_ACTION = new Actions();
    65 
    65 
       
    66     /**
       
    67      * The collapsed icon.
       
    68      */
    66     transient protected Icon        collapsedIcon;
    69     transient protected Icon        collapsedIcon;
       
    70     /**
       
    71      * The expanded icon.
       
    72      */
    67     transient protected Icon        expandedIcon;
    73     transient protected Icon        expandedIcon;
    68 
    74 
    69     /**
    75     /**
    70       * Color used to draw hash marks.  If <code>null</code> no hash marks
    76       * Color used to draw hash marks.  If <code>null</code> no hash marks
    71       * will be drawn.
    77       * will be drawn.
   208      * A temporary variable for communication between startEditingOnRelease
   214      * A temporary variable for communication between startEditingOnRelease
   209      * and startEditing.
   215      * and startEditing.
   210      */
   216      */
   211     private MouseEvent releaseEvent;
   217     private MouseEvent releaseEvent;
   212 
   218 
       
   219     /**
       
   220      * Constructs a new instance of {@code BasicTreeUI}.
       
   221      *
       
   222      * @param x a component
       
   223      * @return a new instance of {@code BasicTreeUI}
       
   224      */
   213     public static ComponentUI createUI(JComponent x) {
   225     public static ComponentUI createUI(JComponent x) {
   214         return new BasicTreeUI();
   226         return new BasicTreeUI();
   215     }
   227     }
   216 
   228 
   217 
   229 
   277         map.put(TransferHandler.getCutAction());
   289         map.put(TransferHandler.getCutAction());
   278         map.put(TransferHandler.getCopyAction());
   290         map.put(TransferHandler.getCopyAction());
   279         map.put(TransferHandler.getPasteAction());
   291         map.put(TransferHandler.getPasteAction());
   280     }
   292     }
   281 
   293 
   282 
   294     /**
       
   295      * Constructs a new instance of {@code BasicTreeUI}.
       
   296      */
   283     public BasicTreeUI() {
   297     public BasicTreeUI() {
   284         super();
   298         super();
   285     }
   299     }
   286 
   300 
       
   301     /**
       
   302      * Returns the hash color.
       
   303      *
       
   304      * @return the hash color
       
   305      */
   287     protected Color getHashColor() {
   306     protected Color getHashColor() {
   288         return hashColor;
   307         return hashColor;
   289     }
   308     }
   290 
   309 
       
   310     /**
       
   311      * Sets the hash color.
       
   312      *
       
   313      * @param color the hash color
       
   314      */
   291     protected void setHashColor(Color color) {
   315     protected void setHashColor(Color color) {
   292         hashColor = color;
   316         hashColor = color;
   293     }
   317     }
   294 
   318 
       
   319     /**
       
   320      * Sets the left child indent.
       
   321      *
       
   322      * @param newAmount the left child indent
       
   323      */
   295     public void setLeftChildIndent(int newAmount) {
   324     public void setLeftChildIndent(int newAmount) {
   296         leftChildIndent = newAmount;
   325         leftChildIndent = newAmount;
   297         totalChildIndent = leftChildIndent + rightChildIndent;
   326         totalChildIndent = leftChildIndent + rightChildIndent;
   298         if(treeState != null)
   327         if(treeState != null)
   299             treeState.invalidateSizes();
   328             treeState.invalidateSizes();
   300         updateSize();
   329         updateSize();
   301     }
   330     }
   302 
   331 
       
   332     /**
       
   333      * Returns the left child indent.
       
   334      *
       
   335      * @return the left child indent
       
   336      */
   303     public int getLeftChildIndent() {
   337     public int getLeftChildIndent() {
   304         return leftChildIndent;
   338         return leftChildIndent;
   305     }
   339     }
   306 
   340 
       
   341     /**
       
   342      * Sets the right child indent.
       
   343      *
       
   344      * @param newAmount the right child indent
       
   345      */
   307     public void setRightChildIndent(int newAmount) {
   346     public void setRightChildIndent(int newAmount) {
   308         rightChildIndent = newAmount;
   347         rightChildIndent = newAmount;
   309         totalChildIndent = leftChildIndent + rightChildIndent;
   348         totalChildIndent = leftChildIndent + rightChildIndent;
   310         if(treeState != null)
   349         if(treeState != null)
   311             treeState.invalidateSizes();
   350             treeState.invalidateSizes();
   312         updateSize();
   351         updateSize();
   313     }
   352     }
   314 
   353 
       
   354     /**
       
   355      * Returns the right child indent.
       
   356      *
       
   357      * @return the right child indent
       
   358      */
   315     public int getRightChildIndent() {
   359     public int getRightChildIndent() {
   316         return rightChildIndent;
   360         return rightChildIndent;
   317     }
   361     }
   318 
   362 
       
   363     /**
       
   364      * Sets the expanded icon.
       
   365      *
       
   366      * @param newG the expanded icon
       
   367      */
   319     public void setExpandedIcon(Icon newG) {
   368     public void setExpandedIcon(Icon newG) {
   320         expandedIcon = newG;
   369         expandedIcon = newG;
   321     }
   370     }
   322 
   371 
       
   372     /**
       
   373      * Returns the expanded icon.
       
   374      *
       
   375      * @return the expanded icon
       
   376      */
   323     public Icon getExpandedIcon() {
   377     public Icon getExpandedIcon() {
   324         return expandedIcon;
   378         return expandedIcon;
   325     }
   379     }
   326 
   380 
       
   381     /**
       
   382      * Sets the collapsed icon.
       
   383      *
       
   384      * @param newG the collapsed icon
       
   385      */
   327     public void setCollapsedIcon(Icon newG) {
   386     public void setCollapsedIcon(Icon newG) {
   328         collapsedIcon = newG;
   387         collapsedIcon = newG;
   329     }
   388     }
   330 
   389 
       
   390     /**
       
   391      * Returns the collapsed icon.
       
   392      *
       
   393      * @return the collapsed icon
       
   394      */
   331     public Icon getCollapsedIcon() {
   395     public Icon getCollapsedIcon() {
   332         return collapsedIcon;
   396         return collapsedIcon;
   333     }
   397     }
   334 
   398 
   335     //
   399     //
   338     // call these methods on the JTree.
   402     // call these methods on the JTree.
   339     //
   403     //
   340 
   404 
   341     /**
   405     /**
   342      * Updates the componentListener, if necessary.
   406      * Updates the componentListener, if necessary.
       
   407      *
       
   408      * @param largeModel the new value
   343      */
   409      */
   344     protected void setLargeModel(boolean largeModel) {
   410     protected void setLargeModel(boolean largeModel) {
   345         if(getRowHeight() < 1)
   411         if(getRowHeight() < 1)
   346             largeModel = false;
   412             largeModel = false;
   347         if(this.largeModel != largeModel) {
   413         if(this.largeModel != largeModel) {
   352             updateLayoutCacheExpandedNodesIfNecessary();
   418             updateLayoutCacheExpandedNodesIfNecessary();
   353             updateSize();
   419             updateSize();
   354         }
   420         }
   355     }
   421     }
   356 
   422 
       
   423     /**
       
   424      * Returns {@code true} if large model is set.
       
   425      *
       
   426      * @return {@code true} if large model is set
       
   427      */
   357     protected boolean isLargeModel() {
   428     protected boolean isLargeModel() {
   358         return largeModel;
   429         return largeModel;
   359     }
   430     }
   360 
   431 
   361     /**
   432     /**
   362      * Sets the row height, this is forwarded to the treeState.
   433      * Sets the row height, this is forwarded to the treeState.
       
   434      *
       
   435      * @param rowHeight the row height
   363      */
   436      */
   364     protected void setRowHeight(int rowHeight) {
   437     protected void setRowHeight(int rowHeight) {
   365         completeEditing();
   438         completeEditing();
   366         if(treeState != null) {
   439         if(treeState != null) {
   367             setLargeModel(tree.isLargeModel());
   440             setLargeModel(tree.isLargeModel());
   368             treeState.setRowHeight(rowHeight);
   441             treeState.setRowHeight(rowHeight);
   369             updateSize();
   442             updateSize();
   370         }
   443         }
   371     }
   444     }
   372 
   445 
       
   446     /**
       
   447      * Returns the row height.
       
   448      *
       
   449      * @return the row height
       
   450      */
   373     protected int getRowHeight() {
   451     protected int getRowHeight() {
   374         return (tree == null) ? -1 : tree.getRowHeight();
   452         return (tree == null) ? -1 : tree.getRowHeight();
   375     }
   453     }
   376 
   454 
   377     /**
   455     /**
   378      * Sets the TreeCellRenderer to <code>tcr</code>. This invokes
   456      * Sets the {@code TreeCellRenderer} to {@code tcr}. This invokes
   379      * <code>updateRenderer</code>.
   457      * {@code updateRenderer}.
       
   458      *
       
   459      * @param tcr the new value
   380      */
   460      */
   381     protected void setCellRenderer(TreeCellRenderer tcr) {
   461     protected void setCellRenderer(TreeCellRenderer tcr) {
   382         completeEditing();
   462         completeEditing();
   383         updateRenderer();
   463         updateRenderer();
   384         if(treeState != null) {
   464         if(treeState != null) {
   386             updateSize();
   466             updateSize();
   387         }
   467         }
   388     }
   468     }
   389 
   469 
   390     /**
   470     /**
   391      * Return currentCellRenderer, which will either be the trees
   471      * Return {@code currentCellRenderer}, which will either be the trees
   392      * renderer, or defaultCellRenderer, which ever wasn't null.
   472      * renderer, or {@code defaultCellRenderer}, which ever wasn't null.
       
   473      *
       
   474      * @return an instance of {@code TreeCellRenderer}
   393      */
   475      */
   394     protected TreeCellRenderer getCellRenderer() {
   476     protected TreeCellRenderer getCellRenderer() {
   395         return currentCellRenderer;
   477         return currentCellRenderer;
   396     }
   478     }
   397 
   479 
   398     /**
   480     /**
   399      * Sets the TreeModel.
   481      * Sets the {@code TreeModel}.
       
   482      *
       
   483      * @param model the new value
   400      */
   484      */
   401     protected void setModel(TreeModel model) {
   485     protected void setModel(TreeModel model) {
   402         completeEditing();
   486         completeEditing();
   403         if(treeModel != null && treeModelListener != null)
   487         if(treeModel != null && treeModelListener != null)
   404             treeModel.removeTreeModelListener(treeModelListener);
   488             treeModel.removeTreeModelListener(treeModelListener);
   412             updateLayoutCacheExpandedNodesIfNecessary();
   496             updateLayoutCacheExpandedNodesIfNecessary();
   413             updateSize();
   497             updateSize();
   414         }
   498         }
   415     }
   499     }
   416 
   500 
       
   501     /**
       
   502      * Returns the tree model.
       
   503      *
       
   504      * @return the tree model
       
   505      */
   417     protected TreeModel getModel() {
   506     protected TreeModel getModel() {
   418         return treeModel;
   507         return treeModel;
   419     }
   508     }
   420 
   509 
   421     /**
   510     /**
   422      * Sets the root to being visible.
   511      * Sets the root to being visible.
       
   512      *
       
   513      * @param newValue the new value
   423      */
   514      */
   424     protected void setRootVisible(boolean newValue) {
   515     protected void setRootVisible(boolean newValue) {
   425         completeEditing();
   516         completeEditing();
   426         updateDepthOffset();
   517         updateDepthOffset();
   427         if(treeState != null) {
   518         if(treeState != null) {
   429             treeState.invalidateSizes();
   520             treeState.invalidateSizes();
   430             updateSize();
   521             updateSize();
   431         }
   522         }
   432     }
   523     }
   433 
   524 
       
   525     /**
       
   526      * Returns {@code true} if the tree root is visible.
       
   527      *
       
   528      * @return {@code true} if the tree root is visible
       
   529      */
   434     protected boolean isRootVisible() {
   530     protected boolean isRootVisible() {
   435         return (tree != null) ? tree.isRootVisible() : false;
   531         return (tree != null) ? tree.isRootVisible() : false;
   436     }
   532     }
   437 
   533 
   438     /**
   534     /**
   439      * Determines whether the node handles are to be displayed.
   535      * Determines whether the node handles are to be displayed.
       
   536      *
       
   537      * @param newValue the new value
   440      */
   538      */
   441     protected void setShowsRootHandles(boolean newValue) {
   539     protected void setShowsRootHandles(boolean newValue) {
   442         completeEditing();
   540         completeEditing();
   443         updateDepthOffset();
   541         updateDepthOffset();
   444         if(treeState != null) {
   542         if(treeState != null) {
   445             treeState.invalidateSizes();
   543             treeState.invalidateSizes();
   446             updateSize();
   544             updateSize();
   447         }
   545         }
   448     }
   546     }
   449 
   547 
       
   548     /**
       
   549      * Returns {@code true} if the root handles are to be displayed.
       
   550      *
       
   551      * @return {@code true} if the root handles are to be displayed
       
   552      */
   450     protected boolean getShowsRootHandles() {
   553     protected boolean getShowsRootHandles() {
   451         return (tree != null) ? tree.getShowsRootHandles() : false;
   554         return (tree != null) ? tree.getShowsRootHandles() : false;
   452     }
   555     }
   453 
   556 
   454     /**
   557     /**
   455      * Sets the cell editor.
   558      * Sets the cell editor.
       
   559      *
       
   560      * @param editor the new cell editor
   456      */
   561      */
   457     protected void setCellEditor(TreeCellEditor editor) {
   562     protected void setCellEditor(TreeCellEditor editor) {
   458         updateCellEditor();
   563         updateCellEditor();
   459     }
   564     }
   460 
   565 
       
   566     /**
       
   567      * Returns an instance of {@code TreeCellEditor}.
       
   568      *
       
   569      * @return an instance of {@code TreeCellEditor}
       
   570      */
   461     protected TreeCellEditor getCellEditor() {
   571     protected TreeCellEditor getCellEditor() {
   462         return (tree != null) ? tree.getCellEditor() : null;
   572         return (tree != null) ? tree.getCellEditor() : null;
   463     }
   573     }
   464 
   574 
   465     /**
   575     /**
   466      * Configures the receiver to allow, or not allow, editing.
   576      * Configures the receiver to allow, or not allow, editing.
       
   577      *
       
   578      * @param newValue the new value
   467      */
   579      */
   468     protected void setEditable(boolean newValue) {
   580     protected void setEditable(boolean newValue) {
   469         updateCellEditor();
   581         updateCellEditor();
   470     }
   582     }
   471 
   583 
       
   584     /**
       
   585      * Returns {@code true} if the tree is editable.
       
   586      *
       
   587      * @return {@code true} if the tree is editable
       
   588      */
   472     protected boolean isEditable() {
   589     protected boolean isEditable() {
   473         return (tree != null) ? tree.isEditable() : false;
   590         return (tree != null) ? tree.isEditable() : false;
   474     }
   591     }
   475 
   592 
   476     /**
   593     /**
   477      * Resets the selection model. The appropriate listener are installed
   594      * Resets the selection model. The appropriate listener are installed
   478      * on the model.
   595      * on the model.
       
   596      *
       
   597      * @param newLSM new selection model
   479      */
   598      */
   480     protected void setSelectionModel(TreeSelectionModel newLSM) {
   599     protected void setSelectionModel(TreeSelectionModel newLSM) {
   481         completeEditing();
   600         completeEditing();
   482         if(selectionModelPropertyChangeListener != null &&
   601         if(selectionModelPropertyChangeListener != null &&
   483            treeSelectionModel != null)
   602            treeSelectionModel != null)
   501             treeState.setSelectionModel(null);
   620             treeState.setSelectionModel(null);
   502         if(tree != null)
   621         if(tree != null)
   503             tree.repaint();
   622             tree.repaint();
   504     }
   623     }
   505 
   624 
       
   625     /**
       
   626      * Returns the tree selection model.
       
   627      *
       
   628      * @return the tree selection model
       
   629      */
   506     protected TreeSelectionModel getSelectionModel() {
   630     protected TreeSelectionModel getSelectionModel() {
   507         return treeSelectionModel;
   631         return treeSelectionModel;
   508     }
   632     }
   509 
   633 
   510     //
   634     //
   647 
   771 
   648         completeUIInstall();
   772         completeUIInstall();
   649     }
   773     }
   650 
   774 
   651     /**
   775     /**
   652      * Invoked after the <code>tree</code> instance variable has been
   776      * Invoked after the {@code tree} instance variable has been
   653      * set, but before any defaults/listeners have been installed.
   777      * set, but before any defaults/listeners have been installed.
   654      */
   778      */
   655     protected void prepareForUIInstall() {
   779     protected void prepareForUIInstall() {
   656         drawingCache = new Hashtable<TreePath,Boolean>(7);
   780         drawingCache = new Hashtable<TreePath,Boolean>(7);
   657 
   781 
   688         configureLayoutCache();
   812         configureLayoutCache();
   689 
   813 
   690         updateSize();
   814         updateSize();
   691     }
   815     }
   692 
   816 
       
   817     /**
       
   818      * Installs default properties.
       
   819      */
   693     protected void installDefaults() {
   820     protected void installDefaults() {
   694         if(tree.getBackground() == null ||
   821         if(tree.getBackground() == null ||
   695            tree.getBackground() instanceof UIResource) {
   822            tree.getBackground() instanceof UIResource) {
   696             tree.setBackground(UIManager.getColor("Tree.background"));
   823             tree.setBackground(UIManager.getColor("Tree.background"));
   697         }
   824         }
   737             LookAndFeel.installProperty(tree,
   864             LookAndFeel.installProperty(tree,
   738                     JTree.SHOWS_ROOT_HANDLES_PROPERTY, showsRootHandles);
   865                     JTree.SHOWS_ROOT_HANDLES_PROPERTY, showsRootHandles);
   739         }
   866         }
   740     }
   867     }
   741 
   868 
       
   869     /**
       
   870      * Registers listeners.
       
   871      */
   742     protected void installListeners() {
   872     protected void installListeners() {
   743         if ( (propertyChangeListener = createPropertyChangeListener())
   873         if ( (propertyChangeListener = createPropertyChangeListener())
   744              != null ) {
   874              != null ) {
   745             tree.addPropertyChangeListener(propertyChangeListener);
   875             tree.addPropertyChangeListener(propertyChangeListener);
   746         }
   876         }
   785         }
   915         }
   786 
   916 
   787         LookAndFeel.installProperty(tree, "opaque", Boolean.TRUE);
   917         LookAndFeel.installProperty(tree, "opaque", Boolean.TRUE);
   788     }
   918     }
   789 
   919 
       
   920     /**
       
   921      * Registers keyboard actions.
       
   922      */
   790     protected void installKeyboardActions() {
   923     protected void installKeyboardActions() {
   791         InputMap km = getInputMap(JComponent.
   924         InputMap km = getInputMap(JComponent.
   792                                   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
   925                                   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
   793 
   926 
   794         SwingUtilities.replaceUIInputMap(tree, JComponent.
   927         SwingUtilities.replaceUIInputMap(tree, JComponent.
   835     //
   968     //
   836     // Create methods.
   969     // Create methods.
   837     //
   970     //
   838 
   971 
   839     /**
   972     /**
   840      * Creates an instance of NodeDimensions that is able to determine
   973      * Creates an instance of {@code NodeDimensions} that is able to determine
   841      * the size of a given node in the tree.
   974      * the size of a given node in the tree.
       
   975      *
       
   976      * @return an instance of {@code NodeDimensions}
   842      */
   977      */
   843     protected AbstractLayoutCache.NodeDimensions createNodeDimensions() {
   978     protected AbstractLayoutCache.NodeDimensions createNodeDimensions() {
   844         return new NodeDimensionsHandler();
   979         return new NodeDimensionsHandler();
   845     }
   980     }
   846 
   981 
   847     /**
   982     /**
   848      * Creates a listener that is responsible that updates the UI based on
   983      * Creates a listener that is responsible that updates the UI based on
   849      * how the tree changes.
   984      * how the tree changes.
       
   985      *
       
   986      * @return an instance of the {@code PropertyChangeListener}
   850      */
   987      */
   851     protected PropertyChangeListener createPropertyChangeListener() {
   988     protected PropertyChangeListener createPropertyChangeListener() {
   852         return getHandler();
   989         return getHandler();
   853     }
   990     }
   854 
   991 
   860     }
   997     }
   861 
   998 
   862     /**
   999     /**
   863      * Creates the listener responsible for updating the selection based on
  1000      * Creates the listener responsible for updating the selection based on
   864      * mouse events.
  1001      * mouse events.
       
  1002      *
       
  1003      * @return an instance of the {@code MouseListener}
   865      */
  1004      */
   866     protected MouseListener createMouseListener() {
  1005     protected MouseListener createMouseListener() {
   867         return getHandler();
  1006         return getHandler();
   868     }
  1007     }
   869 
  1008 
   870     /**
  1009     /**
   871      * Creates a listener that is responsible for updating the display
  1010      * Creates a listener that is responsible for updating the display
   872      * when focus is lost/gained.
  1011      * when focus is lost/gained.
       
  1012      *
       
  1013      * @return an instance of the {@code FocusListener}
   873      */
  1014      */
   874     protected FocusListener createFocusListener() {
  1015     protected FocusListener createFocusListener() {
   875         return getHandler();
  1016         return getHandler();
   876     }
  1017     }
   877 
  1018 
   878     /**
  1019     /**
   879      * Creates the listener reponsible for getting key events from
  1020      * Creates the listener responsible for getting key events from
   880      * the tree.
  1021      * the tree.
       
  1022      *
       
  1023      * @return an instance of the {@code KeyListener}
   881      */
  1024      */
   882     protected KeyListener createKeyListener() {
  1025     protected KeyListener createKeyListener() {
   883         return getHandler();
  1026         return getHandler();
   884     }
  1027     }
   885 
  1028 
   886     /**
  1029     /**
   887      * Creates the listener responsible for getting property change
  1030      * Creates the listener responsible for getting property change
   888      * events from the selection model.
  1031      * events from the selection model.
       
  1032      *
       
  1033      * @return an instance of the {@code PropertyChangeListener}
   889      */
  1034      */
   890     protected PropertyChangeListener createSelectionModelPropertyChangeListener() {
  1035     protected PropertyChangeListener createSelectionModelPropertyChangeListener() {
   891         return getHandler();
  1036         return getHandler();
   892     }
  1037     }
   893 
  1038 
   894     /**
  1039     /**
   895      * Creates the listener that updates the display based on selection change
  1040      * Creates the listener that updates the display based on selection change
   896      * methods.
  1041      * methods.
       
  1042      *
       
  1043      * @return an instance of the {@code TreeSelectionListener}
   897      */
  1044      */
   898     protected TreeSelectionListener createTreeSelectionListener() {
  1045     protected TreeSelectionListener createTreeSelectionListener() {
   899         return getHandler();
  1046         return getHandler();
   900     }
  1047     }
   901 
  1048 
   902     /**
  1049     /**
   903      * Creates a listener to handle events from the current editor.
  1050      * Creates a listener to handle events from the current editor.
       
  1051      *
       
  1052      * @return an instance of the {@code CellEditorListener}
   904      */
  1053      */
   905     protected CellEditorListener createCellEditorListener() {
  1054     protected CellEditorListener createCellEditorListener() {
   906         return getHandler();
  1055         return getHandler();
   907     }
  1056     }
   908 
  1057 
   909     /**
  1058     /**
   910      * Creates and returns a new ComponentHandler. This is used for
  1059      * Creates and returns a new ComponentHandler. This is used for
   911      * the large model to mark the validCachedPreferredSize as invalid
  1060      * the large model to mark the validCachedPreferredSize as invalid
   912      * when the component moves.
  1061      * when the component moves.
       
  1062      *
       
  1063      * @return an instance of the {@code ComponentListener}
   913      */
  1064      */
   914     protected ComponentListener createComponentListener() {
  1065     protected ComponentListener createComponentListener() {
   915         return new ComponentHandler();
  1066         return new ComponentHandler();
   916     }
  1067     }
   917 
  1068 
   918     /**
  1069     /**
   919      * Creates and returns the object responsible for updating the treestate
  1070      * Creates and returns the object responsible for updating the treestate
   920      * when nodes expanded state changes.
  1071      * when nodes expanded state changes.
       
  1072      *
       
  1073      * @return an instance of the {@code TreeExpansionListener}
   921      */
  1074      */
   922     protected TreeExpansionListener createTreeExpansionListener() {
  1075     protected TreeExpansionListener createTreeExpansionListener() {
   923         return getHandler();
  1076         return getHandler();
   924     }
  1077     }
   925 
  1078 
   926     /**
  1079     /**
   927      * Creates the object responsible for managing what is expanded, as
  1080      * Creates the object responsible for managing what is expanded, as
   928      * well as the size of nodes.
  1081      * well as the size of nodes.
       
  1082      *
       
  1083      * @return the object responsible for managing what is expanded
   929      */
  1084      */
   930     protected AbstractLayoutCache createLayoutCache() {
  1085     protected AbstractLayoutCache createLayoutCache() {
   931         if(isLargeModel() && getRowHeight() > 0) {
  1086         if(isLargeModel() && getRowHeight() > 0) {
   932             return new FixedHeightLayoutCache();
  1087             return new FixedHeightLayoutCache();
   933         }
  1088         }
   934         return new VariableHeightLayoutCache();
  1089         return new VariableHeightLayoutCache();
   935     }
  1090     }
   936 
  1091 
   937     /**
  1092     /**
   938      * Returns the renderer pane that renderer components are placed in.
  1093      * Returns the renderer pane that renderer components are placed in.
       
  1094      *
       
  1095      * @return an instance of the {@code CellRendererPane}
   939      */
  1096      */
   940     protected CellRendererPane createCellRendererPane() {
  1097     protected CellRendererPane createCellRendererPane() {
   941         return new CellRendererPane();
  1098         return new CellRendererPane();
   942     }
  1099     }
   943 
  1100 
   944     /**
  1101     /**
   945       * Creates a default cell editor.
  1102      * Creates a default cell editor.
   946       */
  1103      *
       
  1104      * @return a default cell editor
       
  1105      */
   947     protected TreeCellEditor createDefaultCellEditor() {
  1106     protected TreeCellEditor createDefaultCellEditor() {
   948         if(currentCellRenderer != null &&
  1107         if(currentCellRenderer != null &&
   949            (currentCellRenderer instanceof DefaultTreeCellRenderer)) {
  1108            (currentCellRenderer instanceof DefaultTreeCellRenderer)) {
   950             DefaultTreeCellEditor editor = new DefaultTreeCellEditor
  1109             DefaultTreeCellEditor editor = new DefaultTreeCellEditor
   951                         (tree, (DefaultTreeCellRenderer)currentCellRenderer);
  1110                         (tree, (DefaultTreeCellRenderer)currentCellRenderer);
   954         }
  1113         }
   955         return new DefaultTreeCellEditor(tree, null);
  1114         return new DefaultTreeCellEditor(tree, null);
   956     }
  1115     }
   957 
  1116 
   958     /**
  1117     /**
   959       * Returns the default cell renderer that is used to do the
  1118      * Returns the default cell renderer that is used to do the
   960       * stamping of each node.
  1119      * stamping of each node.
   961       */
  1120      *
       
  1121      * @return an instance of {@code TreeCellRenderer}
       
  1122      */
   962     protected TreeCellRenderer createDefaultCellRenderer() {
  1123     protected TreeCellRenderer createDefaultCellRenderer() {
   963         return new DefaultTreeCellRenderer();
  1124         return new DefaultTreeCellRenderer();
   964     }
  1125     }
   965 
  1126 
   966     /**
  1127     /**
   967      * Returns a listener that can update the tree when the model changes.
  1128      * Returns a listener that can update the tree when the model changes.
       
  1129      *
       
  1130      * @return an instance of the {@code TreeModelListener}.
   968      */
  1131      */
   969     protected TreeModelListener createTreeModelListener() {
  1132     protected TreeModelListener createTreeModelListener() {
   970         return getHandler();
  1133         return getHandler();
   971     }
  1134     }
   972 
  1135 
   985         uninstallComponents();
  1148         uninstallComponents();
   986 
  1149 
   987         completeUIUninstall();
  1150         completeUIUninstall();
   988     }
  1151     }
   989 
  1152 
       
  1153     /**
       
  1154      * Invoked before unstallation of UI.
       
  1155      */
   990     protected void prepareForUIUninstall() {
  1156     protected void prepareForUIUninstall() {
   991     }
  1157     }
   992 
  1158 
       
  1159     /**
       
  1160      * Uninstalls UI.
       
  1161      */
   993     protected void completeUIUninstall() {
  1162     protected void completeUIUninstall() {
   994         if(createdRenderer) {
  1163         if(createdRenderer) {
   995             tree.setCellRenderer(null);
  1164             tree.setCellRenderer(null);
   996         }
  1165         }
   997         if(createdCellEditor) {
  1166         if(createdCellEditor) {
  1014         treeSelectionModel = null;
  1183         treeSelectionModel = null;
  1015         treeSelectionListener = null;
  1184         treeSelectionListener = null;
  1016         treeExpansionListener = null;
  1185         treeExpansionListener = null;
  1017     }
  1186     }
  1018 
  1187 
       
  1188     /**
       
  1189      * Uninstalls default properties.
       
  1190      */
  1019     protected void uninstallDefaults() {
  1191     protected void uninstallDefaults() {
  1020         if (tree.getTransferHandler() instanceof UIResource) {
  1192         if (tree.getTransferHandler() instanceof UIResource) {
  1021             tree.setTransferHandler(null);
  1193             tree.setTransferHandler(null);
  1022         }
  1194         }
  1023     }
  1195     }
  1024 
  1196 
       
  1197     /**
       
  1198      * Unregisters listeners.
       
  1199      */
  1025     protected void uninstallListeners() {
  1200     protected void uninstallListeners() {
  1026         if(componentListener != null) {
  1201         if(componentListener != null) {
  1027             tree.removeComponentListener(componentListener);
  1202             tree.removeComponentListener(componentListener);
  1028         }
  1203         }
  1029         if (propertyChangeListener != null) {
  1204         if (propertyChangeListener != null) {
  1057                                (treeSelectionListener);
  1232                                (treeSelectionListener);
  1058         }
  1233         }
  1059         handler = null;
  1234         handler = null;
  1060     }
  1235     }
  1061 
  1236 
       
  1237     /**
       
  1238      * Unregisters keyboard actions.
       
  1239      */
  1062     protected void uninstallKeyboardActions() {
  1240     protected void uninstallKeyboardActions() {
  1063         SwingUtilities.replaceUIActionMap(tree, null);
  1241         SwingUtilities.replaceUIActionMap(tree, null);
  1064         SwingUtilities.replaceUIInputMap(tree, JComponent.
  1242         SwingUtilities.replaceUIInputMap(tree, JComponent.
  1065                                          WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  1243                                          WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  1066                                          null);
  1244                                          null);
  1338         return rect;
  1516         return rect;
  1339     }
  1517     }
  1340 
  1518 
  1341     /**
  1519     /**
  1342      * Paints the horizontal part of the leg. The receiver should
  1520      * Paints the horizontal part of the leg. The receiver should
  1343      * NOT modify <code>clipBounds</code>, or <code>insets</code>.<p>
  1521      * NOT modify {@code clipBounds}, or {@code insets}.<p>
  1344      * NOTE: <code>parentRow</code> can be -1 if the root is not visible.
  1522      * NOTE: {@code parentRow} can be -1 if the root is not visible.
       
  1523      *
       
  1524      * @param g a graphics context
       
  1525      * @param clipBounds a clipped rectangle
       
  1526      * @param insets insets
       
  1527      * @param bounds a bounding rectangle
       
  1528      * @param path a tree path
       
  1529      * @param row a row
       
  1530      * @param isExpanded {@code true} if the path is expanded
       
  1531      * @param hasBeenExpanded {@code true} if the path has been expanded
       
  1532      * @param isLeaf {@code true} if the path is leaf
  1345      */
  1533      */
  1346     protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
  1534     protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
  1347                                             Insets insets, Rectangle bounds,
  1535                                             Insets insets, Rectangle bounds,
  1348                                             TreePath path, int row,
  1536                                             TreePath path, int row,
  1349                                             boolean isExpanded,
  1537                                             boolean isExpanded,
  1395         }
  1583         }
  1396     }
  1584     }
  1397 
  1585 
  1398     /**
  1586     /**
  1399      * Paints the vertical part of the leg. The receiver should
  1587      * Paints the vertical part of the leg. The receiver should
  1400      * NOT modify <code>clipBounds</code>, <code>insets</code>.
  1588      * NOT modify {@code clipBounds}, {@code insets}.
       
  1589      *
       
  1590      * @param g a graphics context
       
  1591      * @param clipBounds a clipped rectangle
       
  1592      * @param insets insets
       
  1593      * @param path a tree path
  1401      */
  1594      */
  1402     protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
  1595     protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
  1403                                           Insets insets, TreePath path) {
  1596                                           Insets insets, TreePath path) {
  1404         if (!paintLines) {
  1597         if (!paintLines) {
  1405             return;
  1598             return;
  1470         }
  1663         }
  1471     }
  1664     }
  1472 
  1665 
  1473     /**
  1666     /**
  1474      * Paints the expand (toggle) part of a row. The receiver should
  1667      * Paints the expand (toggle) part of a row. The receiver should
  1475      * NOT modify <code>clipBounds</code>, or <code>insets</code>.
  1668      * NOT modify {@code clipBounds}, or {@code insets}.
       
  1669      *
       
  1670      * @param g a graphics context
       
  1671      * @param clipBounds a clipped rectangle
       
  1672      * @param insets insets
       
  1673      * @param bounds a bounding rectangle
       
  1674      * @param path a tree path
       
  1675      * @param row a row
       
  1676      * @param isExpanded {@code true} if the path is expanded
       
  1677      * @param hasBeenExpanded {@code true} if the path has been expanded
       
  1678      * @param isLeaf {@code true} if the row is leaf
  1476      */
  1679      */
  1477     protected void paintExpandControl(Graphics g,
  1680     protected void paintExpandControl(Graphics g,
  1478                                       Rectangle clipBounds, Insets insets,
  1681                                       Rectangle clipBounds, Insets insets,
  1479                                       Rectangle bounds, TreePath path,
  1682                                       Rectangle bounds, TreePath path,
  1480                                       int row, boolean isExpanded,
  1683                                       int row, boolean isExpanded,
  1509         }
  1712         }
  1510     }
  1713     }
  1511 
  1714 
  1512     /**
  1715     /**
  1513      * Paints the renderer part of a row. The receiver should
  1716      * Paints the renderer part of a row. The receiver should
  1514      * NOT modify <code>clipBounds</code>, or <code>insets</code>.
  1717      * NOT modify {@code clipBounds}, or {@code insets}.
       
  1718      *
       
  1719      * @param g a graphics context
       
  1720      * @param clipBounds a clipped rectangle
       
  1721      * @param insets insets
       
  1722      * @param bounds a bounding rectangle
       
  1723      * @param path a tree path
       
  1724      * @param row a row
       
  1725      * @param isExpanded {@code true} if the path is expanded
       
  1726      * @param hasBeenExpanded {@code true} if the path has been expanded
       
  1727      * @param isLeaf {@code true} if the path is leaf
  1515      */
  1728      */
  1516     protected void paintRow(Graphics g, Rectangle clipBounds,
  1729     protected void paintRow(Graphics g, Rectangle clipBounds,
  1517                             Insets insets, Rectangle bounds, TreePath path,
  1730                             Insets insets, Rectangle bounds, TreePath path,
  1518                             int row, boolean isExpanded,
  1731                             int row, boolean isExpanded,
  1519                             boolean hasBeenExpanded, boolean isLeaf) {
  1732                             boolean hasBeenExpanded, boolean isLeaf) {
  1539         rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y,
  1752         rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y,
  1540                                     bounds.width, bounds.height, true);
  1753                                     bounds.width, bounds.height, true);
  1541     }
  1754     }
  1542 
  1755 
  1543     /**
  1756     /**
  1544      * Returns true if the expand (toggle) control should be drawn for
  1757      * Returns {@code true} if the expand (toggle) control should be drawn for
  1545      * the specified row.
  1758      * the specified row.
       
  1759      *
       
  1760      * @param path a tree path
       
  1761      * @param row a row
       
  1762      * @param isExpanded {@code true} if the path is expanded
       
  1763      * @param hasBeenExpanded {@code true} if the path has been expanded
       
  1764      * @param isLeaf {@code true} if the row is leaf
       
  1765      * @return {@code true} if the expand (toggle) control should be drawn
       
  1766      *         for the specified row
  1546      */
  1767      */
  1547     protected boolean shouldPaintExpandControl(TreePath path, int row,
  1768     protected boolean shouldPaintExpandControl(TreePath path, int row,
  1548                                                boolean isExpanded,
  1769                                                boolean isExpanded,
  1549                                                boolean hasBeenExpanded,
  1770                                                boolean hasBeenExpanded,
  1550                                                boolean isLeaf) {
  1771                                                boolean isLeaf) {
  1559         return true;
  1780         return true;
  1560     }
  1781     }
  1561 
  1782 
  1562     /**
  1783     /**
  1563      * Paints a vertical line.
  1784      * Paints a vertical line.
       
  1785      *
       
  1786      * @param g a graphics context
       
  1787      * @param c a component
       
  1788      * @param x an X coordinate
       
  1789      * @param top an Y1 coordinate
       
  1790      * @param bottom an Y2 coordinate
  1564      */
  1791      */
  1565     protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
  1792     protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
  1566                                     int bottom) {
  1793                                     int bottom) {
  1567         if (lineTypeDashed) {
  1794         if (lineTypeDashed) {
  1568             drawDashedVerticalLine(g, x, top, bottom);
  1795             drawDashedVerticalLine(g, x, top, bottom);
  1571         }
  1798         }
  1572     }
  1799     }
  1573 
  1800 
  1574     /**
  1801     /**
  1575      * Paints a horizontal line.
  1802      * Paints a horizontal line.
       
  1803      *
       
  1804      * @param g a graphics context
       
  1805      * @param c a component
       
  1806      * @param y an Y coordinate
       
  1807      * @param left an X1 coordinate
       
  1808      * @param right an X2 coordinate
  1576      */
  1809      */
  1577     protected void paintHorizontalLine(Graphics g, JComponent c, int y,
  1810     protected void paintHorizontalLine(Graphics g, JComponent c, int y,
  1578                                       int left, int right) {
  1811                                       int left, int right) {
  1579         if (lineTypeDashed) {
  1812         if (lineTypeDashed) {
  1580             drawDashedHorizontalLine(g, y, left, right);
  1813             drawDashedHorizontalLine(g, y, left, right);
  1584     }
  1817     }
  1585 
  1818 
  1586     /**
  1819     /**
  1587      * The vertical element of legs between nodes starts at the bottom of the
  1820      * The vertical element of legs between nodes starts at the bottom of the
  1588      * parent node by default.  This method makes the leg start below that.
  1821      * parent node by default.  This method makes the leg start below that.
       
  1822      *
       
  1823      * @return the vertical leg buffer
  1589      */
  1824      */
  1590     protected int getVerticalLegBuffer() {
  1825     protected int getVerticalLegBuffer() {
  1591         return 0;
  1826         return 0;
  1592     }
  1827     }
  1593 
  1828 
  1594     /**
  1829     /**
  1595      * The horizontal element of legs between nodes starts at the
  1830      * The horizontal element of legs between nodes starts at the
  1596      * right of the left-hand side of the child node by default.  This
  1831      * right of the left-hand side of the child node by default.  This
  1597      * method makes the leg end before that.
  1832      * method makes the leg end before that.
       
  1833      *
       
  1834      * @return the horizontal leg buffer
  1598      */
  1835      */
  1599     protected int getHorizontalLegBuffer() {
  1836     protected int getHorizontalLegBuffer() {
  1600         return 0;
  1837         return 0;
  1601     }
  1838     }
  1602 
  1839 
  1608 
  1845 
  1609     //
  1846     //
  1610     // Generic painting methods
  1847     // Generic painting methods
  1611     //
  1848     //
  1612 
  1849 
  1613     // Draws the icon centered at (x,y)
  1850     /**
       
  1851      * Draws the {@code icon} centered at (x,y).
       
  1852      *
       
  1853      * @param c a component
       
  1854      * @param graphics a graphics context
       
  1855      * @param icon an icon
       
  1856      * @param x an X coordinate
       
  1857      * @param y an Y coordinate
       
  1858      */
  1614     protected void drawCentered(Component c, Graphics graphics, Icon icon,
  1859     protected void drawCentered(Component c, Graphics graphics, Icon icon,
  1615                                 int x, int y) {
  1860                                 int x, int y) {
  1616         icon.paintIcon(c, graphics,
  1861         icon.paintIcon(c, graphics,
  1617                       findCenteredX(x, icon.getIconWidth()),
  1862                       findCenteredX(x, icon.getIconWidth()),
  1618                       y - icon.getIconHeight() / 2);
  1863                       y - icon.getIconHeight() / 2);
  1683             }
  1928             }
  1684         }
  1929         }
  1685     }
  1930     }
  1686 
  1931 
  1687     /**
  1932     /**
  1688      * Updates the expanded state of all the descendants of <code>path</code>
  1933      * Updates the expanded state of all the descendants of {@code path}
  1689      * by getting the expanded descendants from the tree and forwarding
  1934      * by getting the expanded descendants from the tree and forwarding
  1690      * to the tree state.
  1935      * to the tree state.
       
  1936      *
       
  1937      * @param path a tree path
  1691      */
  1938      */
  1692     protected void updateExpandedDescendants(TreePath path) {
  1939     protected void updateExpandedDescendants(TreePath path) {
  1693         completeEditing();
  1940         completeEditing();
  1694         if(treeState != null) {
  1941         if(treeState != null) {
  1695             treeState.setExpandedState(path, true);
  1942             treeState.setExpandedState(path, true);
  1706             updateSize();
  1953             updateSize();
  1707         }
  1954         }
  1708     }
  1955     }
  1709 
  1956 
  1710     /**
  1957     /**
  1711      * Returns a path to the last child of <code>parent</code>.
  1958      * Returns a path to the last child of {@code parent}.
       
  1959      *
       
  1960      * @param parent a tree path
       
  1961      * @return a path to the last child of {@code parent}
  1712      */
  1962      */
  1713     protected TreePath getLastChildPath(TreePath parent) {
  1963     protected TreePath getLastChildPath(TreePath parent) {
  1714         if(treeModel != null) {
  1964         if(treeModel != null) {
  1715             int         childCount = treeModel.getChildCount
  1965             int         childCount = treeModel.getChildCount
  1716                 (parent.getLastPathComponent());
  1966                 (parent.getLastPathComponent());
  1904         }
  2154         }
  1905         validCachedPreferredSize = true;
  2155         validCachedPreferredSize = true;
  1906     }
  2156     }
  1907 
  2157 
  1908     /**
  2158     /**
  1909       * Messaged from the VisibleTreeNode after it has been expanded.
  2159      * Messaged from the {@code VisibleTreeNode} after it has been expanded.
  1910       */
  2160      *
       
  2161      * @param path a tree path
       
  2162      */
  1911     protected void pathWasExpanded(TreePath path) {
  2163     protected void pathWasExpanded(TreePath path) {
  1912         if(tree != null) {
  2164         if(tree != null) {
  1913             tree.fireTreeExpanded(path);
  2165             tree.fireTreeExpanded(path);
  1914         }
  2166         }
  1915     }
  2167     }
  1916 
  2168 
  1917     /**
  2169     /**
  1918       * Messaged from the VisibleTreeNode after it has collapsed.
  2170      * Messaged from the {@code VisibleTreeNode} after it has collapsed.
  1919       */
  2171      *
       
  2172      * @param path a tree path
       
  2173      */
  1920     protected void pathWasCollapsed(TreePath path) {
  2174     protected void pathWasCollapsed(TreePath path) {
  1921         if(tree != null) {
  2175         if(tree != null) {
  1922             tree.fireTreeCollapsed(path);
  2176             tree.fireTreeCollapsed(path);
  1923         }
  2177         }
  1924     }
  2178     }
  1925 
  2179 
  1926     /**
  2180     /**
  1927       * Ensures that the rows identified by beginRow through endRow are
  2181      * Ensures that the rows identified by {@code beginRow} through
  1928       * visible.
  2182      * {@code endRow} are visible.
  1929       */
  2183      *
       
  2184      * @param beginRow the begin row
       
  2185      * @param endRow the end row
       
  2186      */
  1930     protected void ensureRowsAreVisible(int beginRow, int endRow) {
  2187     protected void ensureRowsAreVisible(int beginRow, int endRow) {
  1931         if(tree != null && beginRow >= 0 && endRow < getRowCount(tree)) {
  2188         if(tree != null && beginRow >= 0 && endRow < getRowCount(tree)) {
  1932             boolean scrollVert = DefaultLookup.getBoolean(tree, this,
  2189             boolean scrollVert = DefaultLookup.getBoolean(tree, this,
  1933                               "Tree.scrollsHorizontallyAndVertically", false);
  2190                               "Tree.scrollsHorizontallyAndVertically", false);
  1934             if(beginRow == endRow) {
  2191             if(beginRow == endRow) {
  1967                 }
  2224                 }
  1968             }
  2225             }
  1969         }
  2226         }
  1970     }
  2227     }
  1971 
  2228 
  1972     /** Sets the preferred minimum size.
  2229     /**
  1973       */
  2230      * Sets the preferred minimum size.
       
  2231      *
       
  2232      * @param newSize the new preferred size
       
  2233      */
  1974     public void setPreferredMinSize(Dimension newSize) {
  2234     public void setPreferredMinSize(Dimension newSize) {
  1975         preferredMinSize = newSize;
  2235         preferredMinSize = newSize;
  1976     }
  2236     }
  1977 
  2237 
  1978     /** Returns the minimum preferred size.
  2238     /**
  1979       */
  2239      * Returns the minimum preferred size.
       
  2240      *
       
  2241      * @return the minimum preferred size
       
  2242      */
  1980     public Dimension getPreferredMinSize() {
  2243     public Dimension getPreferredMinSize() {
  1981         if(preferredMinSize == null)
  2244         if(preferredMinSize == null)
  1982             return null;
  2245             return null;
  1983         return new Dimension(preferredMinSize);
  2246         return new Dimension(preferredMinSize);
  1984     }
  2247     }
  1985 
  2248 
  1986     /** Returns the preferred size to properly display the tree,
  2249     /**
  1987       * this is a cover method for getPreferredSize(c, true).
  2250      * Returns the preferred size to properly display the tree,
  1988       */
  2251      * this is a cover method for {@code getPreferredSize(c, true)}.
       
  2252      *
       
  2253      * @param c a component
       
  2254      * @return the preferred size to represent the tree in the component
       
  2255      */
  1989     public Dimension getPreferredSize(JComponent c) {
  2256     public Dimension getPreferredSize(JComponent c) {
  1990         return getPreferredSize(c, true);
  2257         return getPreferredSize(c, true);
  1991     }
  2258     }
  1992 
  2259 
  1993     /** Returns the preferred size to represent the tree in
  2260     /**
  1994       * <I>c</I>.  If <I>checkConsistency</I> is true
  2261      * Returns the preferred size to represent the tree in
  1995       * <b>checkConsistency</b> is messaged first.
  2262      * <I>c</I>.  If <I>checkConsistency</I> is {@code true}
  1996       */
  2263      * <b>checkConsistency</b> is messaged first.
       
  2264      *
       
  2265      * @param c a component
       
  2266      * @param checkConsistency if {@code true} consistency is checked
       
  2267      * @return the preferred size to represent the tree in the component
       
  2268      */
  1997     public Dimension getPreferredSize(JComponent c,
  2269     public Dimension getPreferredSize(JComponent c,
  1998                                       boolean checkConsistency) {
  2270                                       boolean checkConsistency) {
  1999         Dimension       pSize = this.getPreferredMinSize();
  2271         Dimension       pSize = this.getPreferredMinSize();
  2000 
  2272 
  2001         if(!validCachedPreferredSize)
  2273         if(!validCachedPreferredSize)
  2054            was successful. */
  2326            was successful. */
  2055         completeEditing(false, true, false);
  2327         completeEditing(false, true, false);
  2056     }
  2328     }
  2057 
  2329 
  2058     /**
  2330     /**
  2059       * Stops the editing session.  If messageStop is true the editor
  2331      * Stops the editing session. If {@code messageStop} is {@code true} the editor
  2060       * is messaged with stopEditing, if messageCancel is true the
  2332      * is messaged with {@code stopEditing}, if {@code messageCancel}
  2061       * editor is messaged with cancelEditing. If messageTree is true
  2333      * is {@code true} the editor is messaged with {@code cancelEditing}.
  2062       * the treeModel is messaged with valueForPathChanged.
  2334      * If {@code messageTree} is {@code true} the {@code treeModel} is messaged
  2063       */
  2335      * with {@code valueForPathChanged}.
       
  2336      *
       
  2337      * @param messageStop message to stop editing
       
  2338      * @param messageCancel message to cancel editing
       
  2339      * @param messageTree message to tree
       
  2340      */
  2064     protected void completeEditing(boolean messageStop,
  2341     protected void completeEditing(boolean messageStop,
  2065                                    boolean messageCancel,
  2342                                    boolean messageCancel,
  2066                                    boolean messageTree) {
  2343                                    boolean messageTree) {
  2067         if(stopEditingInCompleteEditing && editingComponent != null) {
  2344         if(stopEditingInCompleteEditing && editingComponent != null) {
  2068             Component             oldComponent = editingComponent;
  2345             Component             oldComponent = editingComponent;
  2110             this.releaseEvent = null;
  2387             this.releaseEvent = null;
  2111         }
  2388         }
  2112     }
  2389     }
  2113 
  2390 
  2114     /**
  2391     /**
  2115       * Will start editing for node if there is a cellEditor and
  2392      * Will start editing for node if there is a {@code cellEditor} and
  2116       * shouldSelectCell returns true.<p>
  2393      * {@code shouldSelectCell} returns {@code true}.<p>
  2117       * This assumes that path is valid and visible.
  2394      * This assumes that path is valid and visible.
  2118       */
  2395      *
       
  2396      * @param path a tree path
       
  2397      * @param event a mouse event
       
  2398      * @return {@code true} if the editing is successful
       
  2399      */
  2119     protected boolean startEditing(TreePath path, MouseEvent event) {
  2400     protected boolean startEditing(TreePath path, MouseEvent event) {
  2120         if (isEditing(tree) && tree.getInvokesStopCellEditing() &&
  2401         if (isEditing(tree) && tree.getInvokesStopCellEditing() &&
  2121                                !stopEditing(tree)) {
  2402                                !stopEditing(tree)) {
  2122             return false;
  2403             return false;
  2123         }
  2404         }
  2218     //
  2499     //
  2219     // Following are primarily for handling mouse events.
  2500     // Following are primarily for handling mouse events.
  2220     //
  2501     //
  2221 
  2502 
  2222     /**
  2503     /**
  2223      * If the <code>mouseX</code> and <code>mouseY</code> are in the
  2504      * If the {@code mouseX} and {@code mouseY} are in the
  2224      * expand/collapse region of the <code>row</code>, this will toggle
  2505      * expand/collapse region of the {@code row}, this will toggle
  2225      * the row.
  2506      * the row.
       
  2507      *
       
  2508      * @param path a tree path
       
  2509      * @param mouseX an X coordinate
       
  2510      * @param mouseY an Y coordinate
  2226      */
  2511      */
  2227     protected void checkForClickInExpandControl(TreePath path,
  2512     protected void checkForClickInExpandControl(TreePath path,
  2228                                                 int mouseX, int mouseY) {
  2513                                                 int mouseX, int mouseY) {
  2229       if (isLocationInExpandControl(path, mouseX, mouseY)) {
  2514       if (isLocationInExpandControl(path, mouseX, mouseY)) {
  2230           handleExpandControlClick(path, mouseX, mouseY);
  2515           handleExpandControlClick(path, mouseX, mouseY);
  2231         }
  2516         }
  2232     }
  2517     }
  2233 
  2518 
  2234     /**
  2519     /**
  2235      * Returns true if <code>mouseX</code> and <code>mouseY</code> fall
  2520      * Returns {@code true} if {@code mouseX} and {@code mouseY} fall
  2236      * in the area of row that is used to expand/collapse the node and
  2521      * in the area of row that is used to expand/collapse the node and
  2237      * the node at <code>row</code> does not represent a leaf.
  2522      * the node at {@code row} does not represent a leaf.
       
  2523      *
       
  2524      * @param path a tree path
       
  2525      * @param mouseX an X coordinate
       
  2526      * @param mouseY an Y coordinate
       
  2527      * @return {@code true} if the mouse cursor fall in the area of row that
       
  2528      *         is used to expand/collapse the node and the node is not a leaf.
  2238      */
  2529      */
  2239     protected boolean isLocationInExpandControl(TreePath path,
  2530     protected boolean isLocationInExpandControl(TreePath path,
  2240                                                 int mouseX, int mouseY) {
  2531                                                 int mouseX, int mouseY) {
  2241         if(path != null && !treeModel.isLeaf(path.getLastPathComponent())){
  2532         if(path != null && !treeModel.isLeaf(path.getLastPathComponent())){
  2242             int                     boxWidth;
  2533             int                     boxWidth;
  2263         return false;
  2554         return false;
  2264     }
  2555     }
  2265 
  2556 
  2266     /**
  2557     /**
  2267      * Messaged when the user clicks the particular row, this invokes
  2558      * Messaged when the user clicks the particular row, this invokes
  2268      * toggleExpandState.
  2559      * {@code toggleExpandState}.
       
  2560      *
       
  2561      * @param path a tree path
       
  2562      * @param mouseX an X coordinate
       
  2563      * @param mouseY an Y coordinate
  2269      */
  2564      */
  2270     protected void handleExpandControlClick(TreePath path, int mouseX,
  2565     protected void handleExpandControlClick(TreePath path, int mouseX,
  2271                                             int mouseY) {
  2566                                             int mouseY) {
  2272         toggleExpandState(path);
  2567         toggleExpandState(path);
  2273     }
  2568     }
  2274 
  2569 
  2275     /**
  2570     /**
  2276      * Expands path if it is not expanded, or collapses row if it is expanded.
  2571      * Expands path if it is not expanded, or collapses row if it is expanded.
  2277      * If expanding a path and JTree scrolls on expand, ensureRowsAreVisible
  2572      * If expanding a path and {@code JTree} scrolls on expand,
  2278      * is invoked to scroll as many of the children to visible as possible
  2573      * {@code ensureRowsAreVisible} is invoked to scroll as many of the children
  2279      * (tries to scroll to last visible descendant of path).
  2574      * to visible as possible (tries to scroll to last visible descendant of path).
       
  2575      *
       
  2576      * @param path a tree path
  2280      */
  2577      */
  2281     protected void toggleExpandState(TreePath path) {
  2578     protected void toggleExpandState(TreePath path) {
  2282         if(!tree.isExpanded(path)) {
  2579         if(!tree.isExpanded(path)) {
  2283             int       row = getRowForPath(tree, path);
  2580             int       row = getRowForPath(tree, path);
  2284 
  2581 
  2297             updateSize();
  2594             updateSize();
  2298         }
  2595         }
  2299     }
  2596     }
  2300 
  2597 
  2301     /**
  2598     /**
  2302      * Returning true signifies a mouse event on the node should toggle
  2599      * Returning {@code true} signifies a mouse event on the node should toggle
  2303      * the selection of only the row under mouse.
  2600      * the selection of only the row under mouse.
       
  2601      *
       
  2602      * @param event a mouse event
       
  2603      * @return {@code true} if a mouse event on the node should toggle the selection
  2304      */
  2604      */
  2305     protected boolean isToggleSelectionEvent(MouseEvent event) {
  2605     protected boolean isToggleSelectionEvent(MouseEvent event) {
  2306         return (SwingUtilities.isLeftMouseButton(event) &&
  2606         return (SwingUtilities.isLeftMouseButton(event) &&
  2307                 BasicGraphicsUtils.isMenuShortcutKeyDown(event));
  2607                 BasicGraphicsUtils.isMenuShortcutKeyDown(event));
  2308     }
  2608     }
  2309 
  2609 
  2310     /**
  2610     /**
  2311      * Returning true signifies a mouse event on the node should select
  2611      * Returning {@code true} signifies a mouse event on the node should select
  2312      * from the anchor point.
  2612      * from the anchor point.
       
  2613      *
       
  2614      * @param event a mouse event
       
  2615      * @return {@code true} if a mouse event on the node should select
       
  2616      *         from the anchor point
  2313      */
  2617      */
  2314     protected boolean isMultiSelectEvent(MouseEvent event) {
  2618     protected boolean isMultiSelectEvent(MouseEvent event) {
  2315         return (SwingUtilities.isLeftMouseButton(event) &&
  2619         return (SwingUtilities.isLeftMouseButton(event) &&
  2316                 event.isShiftDown());
  2620                 event.isShiftDown());
  2317     }
  2621     }
  2318 
  2622 
  2319     /**
  2623     /**
  2320      * Returning true indicates the row under the mouse should be toggled
  2624      * Returning {@code true} indicates the row under the mouse should be toggled
  2321      * based on the event. This is invoked after checkForClickInExpandControl,
  2625      * based on the event. This is invoked after {@code checkForClickInExpandControl},
  2322      * implying the location is not in the expand (toggle) control
  2626      * implying the location is not in the expand (toggle) control.
       
  2627      *
       
  2628      * @param event a mouse event
       
  2629      * @return {@code true} if the row under the mouse should be toggled
  2323      */
  2630      */
  2324     protected boolean isToggleEvent(MouseEvent event) {
  2631     protected boolean isToggleEvent(MouseEvent event) {
  2325         if(!SwingUtilities.isLeftMouseButton(event)) {
  2632         if(!SwingUtilities.isLeftMouseButton(event)) {
  2326             return false;
  2633             return false;
  2327         }
  2634         }
  2332         }
  2639         }
  2333         return ((event.getClickCount() % clickCount) == 0);
  2640         return ((event.getClickCount() % clickCount) == 0);
  2334     }
  2641     }
  2335 
  2642 
  2336     /**
  2643     /**
  2337      * Messaged to update the selection based on a MouseEvent over a
  2644      * Messaged to update the selection based on a {@code MouseEvent} over a
  2338      * particular row. If the event is a toggle selection event, the
  2645      * particular row. If the event is a toggle selection event, the
  2339      * row is either selected, or deselected. If the event identifies
  2646      * row is either selected, or deselected. If the event identifies
  2340      * a multi selection event, the selection is updated from the
  2647      * a multi selection event, the selection is updated from the
  2341      * anchor point. Otherwise the row is selected, and if the event
  2648      * anchor point. Otherwise the row is selected, and if the event
  2342      * specified a toggle event the row is expanded/collapsed.
  2649      * specified a toggle event the row is expanded/collapsed.
       
  2650      *
       
  2651      * @param path the selected path
       
  2652      * @param event the mouse event
  2343      */
  2653      */
  2344     protected void selectPathForEvent(TreePath path, MouseEvent event) {
  2654     protected void selectPathForEvent(TreePath path, MouseEvent event) {
  2345         /* Adjust from the anchor point. */
  2655         /* Adjust from the anchor point. */
  2346         if(isMultiSelectEvent(event)) {
  2656         if(isMultiSelectEvent(event)) {
  2347             TreePath    anchor = getAnchorSelectionPath();
  2657             TreePath    anchor = getAnchorSelectionPath();
  2395             }
  2705             }
  2396         }
  2706         }
  2397     }
  2707     }
  2398 
  2708 
  2399     /**
  2709     /**
  2400      * @return true if the node at <code>row</code> is a leaf.
  2710      * Returns {@code true} if the node at {@code row} is a leaf.
       
  2711      *
       
  2712      * @param row a row
       
  2713      * @return {@code true} if the node at {@code row} is a leaf
  2401      */
  2714      */
  2402     protected boolean isLeaf(int row) {
  2715     protected boolean isLeaf(int row) {
  2403         TreePath          path = getPathForRow(tree, row);
  2716         TreePath          path = getPathForRow(tree, row);
  2404 
  2717 
  2405         if(path != null)
  2718         if(path != null)
  2590             }
  2903             }
  2591             timer.start();
  2904             timer.start();
  2592         }
  2905         }
  2593 
  2906 
  2594         /**
  2907         /**
  2595          * Returns the JScrollPane housing the JTree, or null if one isn't
  2908          * Returns the {@code JScrollPane} housing the {@code JTree},
  2596          * found.
  2909          * or null if one isn't found.
       
  2910          *
       
  2911          * @return the {@code JScrollPane} housing the {@code JTree}
  2597          */
  2912          */
  2598         protected JScrollPane getScrollPane() {
  2913         protected JScrollPane getScrollPane() {
  2599             Component       c = tree.getParent();
  2914             Component       c = tree.getParent();
  2600 
  2915 
  2601             while(c != null && !(c instanceof JScrollPane))
  2916             while(c != null && !(c instanceof JScrollPane))
  2826             }
  3141             }
  2827             return null;
  3142             return null;
  2828         }
  3143         }
  2829 
  3144 
  2830         /**
  3145         /**
  2831          * @return amount to indent the given row.
  3146          * Returns amount to indent the given row.
       
  3147          *
       
  3148          * @param row a row
       
  3149          * @param depth a depth
       
  3150          * @return amount to indent the given row
  2832          */
  3151          */
  2833         protected int getRowX(int row, int depth) {
  3152         protected int getRowX(int row, int depth) {
  2834             return BasicTreeUI.this.getRowX(row, depth);
  3153             return BasicTreeUI.this.getRowX(row, depth);
  2835         }
  3154         }
  2836 
  3155 
  2922         protected int direction;
  3241         protected int direction;
  2923         /** True if the selection is reset, false means only the lead path
  3242         /** True if the selection is reset, false means only the lead path
  2924          * changes. */
  3243          * changes. */
  2925         private boolean changeSelection;
  3244         private boolean changeSelection;
  2926 
  3245 
       
  3246         /**
       
  3247          * Constructs a new instance of {@code TreeTraverseAction}.
       
  3248          *
       
  3249          * @param direction the direction
       
  3250          * @param name the name of action
       
  3251          */
  2927         public TreeTraverseAction(int direction, String name) {
  3252         public TreeTraverseAction(int direction, String name) {
  2928             this(direction, name, true);
  3253             this(direction, name, true);
  2929         }
  3254         }
  2930 
  3255 
  2931         private TreeTraverseAction(int direction, String name,
  3256         private TreeTraverseAction(int direction, String name,
  2954         protected int         direction;
  3279         protected int         direction;
  2955         /** True indicates should set selection from anchor path. */
  3280         /** True indicates should set selection from anchor path. */
  2956         private boolean       addToSelection;
  3281         private boolean       addToSelection;
  2957         private boolean       changeSelection;
  3282         private boolean       changeSelection;
  2958 
  3283 
       
  3284         /**
       
  3285          * Constructs a new instance of {@code TreePageAction}.
       
  3286          *
       
  3287          * @param direction the direction
       
  3288          * @param name the name of action
       
  3289          */
  2959         public TreePageAction(int direction, String name) {
  3290         public TreePageAction(int direction, String name) {
  2960             this(direction, name, false, true);
  3291             this(direction, name, false, true);
  2961         }
  3292         }
  2962 
  3293 
  2963         private TreePageAction(int direction, String name,
  3294         private TreePageAction(int direction, String name,
  2991         /** If true the new item is added to the selection, if false the
  3322         /** If true the new item is added to the selection, if false the
  2992          * selection is reset. */
  3323          * selection is reset. */
  2993         private boolean       addToSelection;
  3324         private boolean       addToSelection;
  2994         private boolean       changeSelection;
  3325         private boolean       changeSelection;
  2995 
  3326 
       
  3327         /**
       
  3328          * Constructs a new instance of {@code TreeIncrementAction}.
       
  3329          *
       
  3330          * @param direction the direction
       
  3331          * @param name the name of action
       
  3332          */
  2996         public TreeIncrementAction(int direction, String name) {
  3333         public TreeIncrementAction(int direction, String name) {
  2997             this(direction, name, false, true);
  3334             this(direction, name, false, true);
  2998         }
  3335         }
  2999 
  3336 
  3000         private TreeIncrementAction(int direction, String name,
  3337         private TreeIncrementAction(int direction, String name,
  3022       * Scrolls either the first or last cell to be visible based on
  3359       * Scrolls either the first or last cell to be visible based on
  3023       * direction.
  3360       * direction.
  3024       */
  3361       */
  3025     @SuppressWarnings("serial") // Superclass is not serializable across versions
  3362     @SuppressWarnings("serial") // Superclass is not serializable across versions
  3026     public class TreeHomeAction extends AbstractAction {
  3363     public class TreeHomeAction extends AbstractAction {
       
  3364         /**
       
  3365          * The direction.
       
  3366          */
  3027         protected int            direction;
  3367         protected int            direction;
  3028         /** Set to true if append to selection. */
  3368         /** Set to true if append to selection. */
  3029         private boolean          addToSelection;
  3369         private boolean          addToSelection;
  3030         private boolean          changeSelection;
  3370         private boolean          changeSelection;
  3031 
  3371 
       
  3372         /**
       
  3373          * Constructs a new instance of {@code TreeHomeAction}.
       
  3374          *
       
  3375          * @param direction the direction
       
  3376          * @param name the name of action
       
  3377          */
  3032         public TreeHomeAction(int direction, String name) {
  3378         public TreeHomeAction(int direction, String name) {
  3033             this(direction, name, false, true);
  3379             this(direction, name, false, true);
  3034         }
  3380         }
  3035 
  3381 
  3036         private TreeHomeAction(int direction, String name,
  3382         private TreeHomeAction(int direction, String name,
  3057     /**
  3403     /**
  3058       * For the first selected row expandedness will be toggled.
  3404       * For the first selected row expandedness will be toggled.
  3059       */
  3405       */
  3060     @SuppressWarnings("serial") // Superclass is not serializable across versions
  3406     @SuppressWarnings("serial") // Superclass is not serializable across versions
  3061     public class TreeToggleAction extends AbstractAction {
  3407     public class TreeToggleAction extends AbstractAction {
       
  3408         /**
       
  3409          * Constructs a new instance of {@code TreeToggleAction}.
       
  3410          *
       
  3411          * @param name the name of action
       
  3412          */
  3062         public TreeToggleAction(String name) {
  3413         public TreeToggleAction(String name) {
  3063         }
  3414         }
  3064 
  3415 
  3065         public void actionPerformed(ActionEvent e) {
  3416         public void actionPerformed(ActionEvent e) {
  3066             if(tree != null) {
  3417             if(tree != null) {
  3077     /**
  3428     /**
  3078      * ActionListener that invokes cancelEditing when action performed.
  3429      * ActionListener that invokes cancelEditing when action performed.
  3079      */
  3430      */
  3080     @SuppressWarnings("serial") // Superclass is not serializable across versions
  3431     @SuppressWarnings("serial") // Superclass is not serializable across versions
  3081     public class TreeCancelEditingAction extends AbstractAction {
  3432     public class TreeCancelEditingAction extends AbstractAction {
       
  3433         /**
       
  3434          * Constructs a new instance of {@code TreeCancelEditingAction}.
       
  3435          *
       
  3436          * @param name the name of action
       
  3437          */
  3082         public TreeCancelEditingAction(String name) {
  3438         public TreeCancelEditingAction(String name) {
  3083         }
  3439         }
  3084 
  3440 
  3085         public void actionPerformed(ActionEvent e) {
  3441         public void actionPerformed(ActionEvent e) {
  3086             if(tree != null) {
  3442             if(tree != null) {
  3108         /** Destination that receives all events. */
  3464         /** Destination that receives all events. */
  3109         protected Component        destination;
  3465         protected Component        destination;
  3110         private Component          focusComponent;
  3466         private Component          focusComponent;
  3111         private boolean            dispatchedEvent;
  3467         private boolean            dispatchedEvent;
  3112 
  3468 
       
  3469         /**
       
  3470          * Constructs a new instance of {@code MouseInputHandler}.
       
  3471          *
       
  3472          * @param source a source component
       
  3473          * @param destination a destination component
       
  3474          * @param event a mouse event
       
  3475          */
  3113         public MouseInputHandler(Component source, Component destination,
  3476         public MouseInputHandler(Component source, Component destination,
  3114                                       MouseEvent event){
  3477                                       MouseEvent event){
  3115             this(source, destination, event, null);
  3478             this(source, destination, event, null);
  3116         }
  3479         }
  3117 
  3480 
  3171 
  3534 
  3172         public void mouseMoved(MouseEvent e) {
  3535         public void mouseMoved(MouseEvent e) {
  3173             removeFromSource();
  3536             removeFromSource();
  3174         }
  3537         }
  3175 
  3538 
       
  3539         /**
       
  3540          * Removes an event from the source.
       
  3541          */
  3176         protected void removeFromSource() {
  3542         protected void removeFromSource() {
  3177             if(source != null) {
  3543             if(source != null) {
  3178                 source.removeMouseListener(this);
  3544                 source.removeMouseListener(this);
  3179                 source.removeMouseMotionListener(this);
  3545                 source.removeMouseMotionListener(this);
  3180                 if (focusComponent != null &&
  3546                 if (focusComponent != null &&