I fixed a couple more problems with JTree that showed up in OpenJump
(yesterday I made a mistake and started OpenJump with the wrong VM).
Mostly they have to do with dealing with null pointers in the UI and
tree related classes. One important piece is that in the
VariableHeightLayoutCache we need to clear the state when calling
setModel(), otherwise we end up with old data in the tables. This was
causing the ClassCastException that was reported.

I fixed some other things that I came upon in the UI, mostly be
subclassing the UI and adding printlns to find out which method calls
which in the RI. I will continue with this soon, to get rid of the
remaining JAPI failures for the BasicTreeUI.

2006-06-06  Roman Kennke  <[EMAIL PROTECTED]>

        PR 27920
        * javax/swing/JTree.java
        (JTree()): Initialize with default model.
        (JTree(TreeModel)): Clear expanded state hashtable. Added comment
        on the updateUI() / setModel() order.
        (setModel): Correctly (un-)setup the listeners. Clear the expanded
        paths.
        * javax/swing/plaf/basic/BasicTreeUI.java
        (BasicTreeUI()): Initialize listeners in installListeners().
        (setModel): Complete editing on model change. Correctly resetup
        the listeners. Update the layout cache accordingly.
        (setShowRootHandles): Complete editing and update layout. Do not
        call back into the JTree, this could cause cycles.
        (prepareForUIInstall): Implemented. Moved some init code from
        installUI() to this method.
        (completeUIInstall): Implemented. Moved some init code from
        installUI() to this method.
        (createDefaultCellEditor): Check for type of renderer, and install
        with null renderer when not DefaultTreeCellRenderer.
        (updateLayoutCacheExpandedNodes): Added null check for tree root
        to avoid NPE.
        (updateRenderer): Call updateEditor().
        (installListeners): Initialize the listeners here. Added some null
        checks to avoid NPEs.
        (installUI): Moved some init code to prepareForUIInstall() and
        completeUIInstall().
        (completeEditing): Return immediately if editing component is null
        or if the setting is to not stop editing on complete editing.
        (checkForClickInExpandControl): Call handleExpandControlClick()
        instead of toggleExpandState() directly.
        (isLocationInExpandControl): Rewritten to correctly determine the
        expand click location.
        (MouseHandler.mousePressed): Rewritten to make better use of the
        instance methods of BasicTreeUI to handle the click.
        (PropertyHandler.propertyChange): Handle model and cell renderer
        updates.
        * javax/swing/tree/DefaultTreeCellEditor.java
        (DefaultTreeCellEditor): Removed initialization of the icon. This
        is done so that the constructor can deal with null renderer as the
        RI does. Maybe this needs more fixing.
        * javax/swing/tree/TreePath.java
        (isDescendant): Fixed this method. The previous version did too
        much and compared the wrong things, which lead to a ClassCastException
        in equals().
        * javax/swing/tree/VariableHeightLayoutCache.java
        (update): Do nothing when model is null.
        (setModel): Clear the tables and update the layout. Added null
        check to prevent NPE.

/Roman

-- 
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: javax/swing/JTree.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTree.java,v
retrieving revision 1.68
diff -u -1 -0 -r1.68 JTree.java
--- javax/swing/JTree.java	6 Jun 2006 15:34:56 -0000	1.68
+++ javax/swing/JTree.java	7 Jun 2006 14:34:00 -0000
@@ -1471,21 +1471,21 @@
    * @see #setUIProperty(String, Object)
    * @see LookAndFeel#installProperty(JComponent, String, Object)
    */
   private boolean clientShowsRootHandlesSet = false;
 
   /**
    * Creates a new <code>JTree</code> object.
    */
   public JTree()
   {
-    this(createTreeModel(null));
+    this(getDefaultTreeModel());
   }
 
   /**
    * Creates a new <code>JTree</code> object.
    * 
    * @param value the initial nodes in the tree
    */
   public JTree(Hashtable value)
   {
     this(createTreeModel(value));
@@ -1506,21 +1506,26 @@
    * 
    * @param model the model to use
    */
   public JTree(TreeModel model)
   {
     setRootVisible(true);
     setSelectionModel(new EmptySelectionModel());
     selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
     
     // The root node appears expanded by default.
-    nodeStates.put(new TreePath(model.getRoot()), EXPANDED);
+    nodeStates = new Hashtable();
+
+    // Install the UI before installing the model. This way we avoid double
+    // initialization of lots of UI and model stuff inside the UI and related
+    // classes. The necessary UI updates are performed via property change
+    // events to the UI.
     updateUI();
     setModel(model);
   }
 
   /**
    * Creates a new <code>JTree</code> object.
    * 
    * @param root the root node
    */
   public JTree(TreeNode root)
@@ -1890,28 +1895,46 @@
   /**
    * Sets the model to use in <code>JTree</code>.
    * 
    * @param model the <code>TreeModel</code> to use
    */
   public void setModel(TreeModel model)
   {
     if (treeModel == model)
       return;
 
+    // Remove listeners from old model.
+    if (treeModel != null && treeModelListener != null)
+      treeModel.removeTreeModelListener(treeModelListener);
+
     // add treeModelListener to the new model
     if (treeModelListener == null)
       treeModelListener = createTreeModelListener();
     if (model != null) // as setModel(null) is allowed
       model.addTreeModelListener(treeModelListener);
 
     TreeModel oldValue = treeModel;
     treeModel = model;
+    clearToggledPaths();
+
+    if (treeModel != null)
+      {
+        if (treeModelListener == null)
+          treeModelListener = createTreeModelListener();
+        if (treeModelListener != null)
+          treeModel.addTreeModelListener(treeModelListener);
+        Object root = treeModel.getRoot();
+        if (root != null && !treeModel.isLeaf(root))
+          {
+            nodeStates.put(new TreePath(root), Boolean.TRUE);
+          }
+      }
 
     firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model);
   }
 
   /**
    * Checks if this <code>JTree</code> object is editable.
    * 
    * @return <code>true</code> if this tree object is editable,
    *         <code>false</code> otherwise
    */
Index: javax/swing/plaf/basic/BasicTreeUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTreeUI.java,v
retrieving revision 1.139
diff -u -1 -0 -r1.139 BasicTreeUI.java
--- javax/swing/plaf/basic/BasicTreeUI.java	25 May 2006 08:51:13 -0000	1.139
+++ javax/swing/plaf/basic/BasicTreeUI.java	7 Jun 2006 14:34:02 -0000
@@ -42,21 +42,20 @@
 import gnu.javax.swing.tree.GnuPath;
 
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Insets;
 import java.awt.Label;
-import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyAdapter;
@@ -300,31 +299,20 @@
   /**
    * Creates a new BasicTreeUI object.
    */
   public BasicTreeUI()
   {
     validCachedPreferredSize = false;
     drawingCache = new Hashtable();
     nodeDimensions = createNodeDimensions();
     configureLayoutCache();
 
-    propertyChangeListener = createPropertyChangeListener();
-    focusListener = createFocusListener();
-    treeSelectionListener = createTreeSelectionListener();
-    mouseListener = createMouseListener();
-    keyListener = createKeyListener();
-    selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener();
-    componentListener = createComponentListener();
-    cellEditorListener = createCellEditorListener();
-    treeExpansionListener = createTreeExpansionListener();
-    treeModelListener = createTreeModelListener();
-
     editingRow = - 1;
     lastSelectedRow = - 1;
   }
 
   /**
    * Returns an instance of the UI delegate for the specified component.
    * 
    * @param c the <code>JComponent</code> for which we need a UI delegate for.
    * @return the <code>ComponentUI</code> for c.
    */
@@ -506,23 +494,36 @@
     return createDefaultCellRenderer();
   }
 
   /**
    * Sets the tree's model.
    * 
    * @param model to set the treeModel to.
    */
   protected void setModel(TreeModel model)
   {
-    tree.setModel(model);
+    completeEditing();
+
+    if (treeModel != null && treeModelListener != null)
+      treeModel.removeTreeModelListener(treeModelListener);
+
     treeModel = tree.getModel();
-    treeState.setModel(treeModel);
+
+    if (treeModel != null && treeModelListener != null)
+      treeModel.addTreeModelListener(treeModelListener);
+
+    if (treeState != null)
+      {
+        treeState.setModel(treeModel);
+        updateLayoutCacheExpandedNodes();
+        updateSize();
+      }
   }
 
   /**
    * Returns the tree's model
    * 
    * @return treeModel
    */
   protected TreeModel getModel()
   {
     return treeModel;
@@ -548,21 +549,27 @@
     return tree.isRootVisible();
   }
 
   /**
    * Determines whether the node handles are to be displayed.
    * 
    * @param newValue sets whether or not node handles should be displayed.
    */
   protected void setShowsRootHandles(boolean newValue)
   {
-    tree.setShowsRootHandles(newValue);
+    completeEditing();
+    updateDepthOffset();
+    if (treeState != null)
+      {
+        treeState.invalidateSizes();
+        updateSize();
+      }
   }
 
   /**
    * Returns true if the node handles are to be displayed.
    * 
    * @return true if the node handles are to be displayed.
    */
   protected boolean getShowsRootHandles()
   {
     return tree.getShowsRootHandles();
@@ -815,33 +822,42 @@
   public TreePath getEditingPath(JTree tree)
   {
     return editingPath;
   }
 
   /**
    * Invoked after the tree instance variable has been set, but before any
    * default/listeners have been installed.
    */
   protected void prepareForUIInstall()
-  throws NotImplementedException
   {
-    // TODO: Implement this properly.
+    lastSelectedRow = -1;
+    preferredSize = new Dimension();
+    largeModel = tree.isLargeModel();
+    preferredSize = new Dimension();
+    setModel(tree.getModel());
   }
 
   /**
    * Invoked from installUI after all the defaults/listeners have been
    * installed.
    */
   protected void completeUIInstall()
-  throws NotImplementedException
   {
-    // TODO: Implement this properly.
+    setShowsRootHandles(tree.getShowsRootHandles());
+    updateRenderer();
+    updateDepthOffset();
+    setSelectionModel(tree.getSelectionModel());
+    treeState = createLayoutCache();
+    treeSelectionModel.setRowMapper(treeState);
+    configureLayoutCache();
+    updateSize();
   }
 
   /**
    * Invoked from uninstallUI after all the defaults/listeners have been
    * uninstalled.
    */
   protected void completeUIUninstall()
   throws NotImplementedException
   {
     // TODO: Implement this properly.
@@ -990,29 +1006,28 @@
     return new CellRendererPane();
   }
 
   /**
    * Creates a default cell editor.
    * 
    * @return the default cell editor.
    */
   protected TreeCellEditor createDefaultCellEditor()
   {
-    if (currentCellRenderer != null)
-      return new DefaultTreeCellEditor(
-                                       tree,
-                                       (DefaultTreeCellRenderer) currentCellRenderer,
-                                       cellEditor);
-    return new DefaultTreeCellEditor(
-                                     tree,
-                                     (DefaultTreeCellRenderer) createDefaultCellRenderer(),
-                                     cellEditor);
+    DefaultTreeCellEditor ed;
+    if (currentCellRenderer != null
+        && currentCellRenderer instanceof DefaultTreeCellRenderer)
+      ed = new DefaultTreeCellEditor(tree,
+                                (DefaultTreeCellRenderer) currentCellRenderer);
+    else
+      ed = new DefaultTreeCellEditor(tree, null);
+    return ed;
   }
 
   /**
    * Returns the default cell renderer that is used to do the stamping of each
    * node.
    * 
    * @return the default cell renderer that is used to do the stamping of each
    *         node.
    */
   protected TreeCellRenderer createDefaultCellRenderer()
@@ -1095,21 +1110,21 @@
   {
     return rightChildIndent / 2;
   }
 
   /**
    * Make all the nodes that are expanded in JTree expanded in LayoutCache. This
    * invokes updateExpandedDescendants with the root path.
    */
   protected void updateLayoutCacheExpandedNodes()
   {
-    if (treeModel != null)
+    if (treeModel != null && treeModel.getRoot() != null)
       updateExpandedDescendants(new TreePath(treeModel.getRoot()));
   }
 
   /**
    * Updates the expanded state of all the descendants of the <code>path</code>
    * by getting the expanded descendants from the tree and forwarding to the
    * tree state.
    * 
    * @param path the path used to update the expanded states
    */
@@ -1154,20 +1169,22 @@
   /**
    * Messaged from the tree we're in when the renderer has changed.
    */
   protected void updateRenderer()
   {
     if (tree != null)
       currentCellRenderer = tree.getCellRenderer();
 
     if (currentCellRenderer == null)
       currentCellRenderer = createDefaultCellRenderer();
+
+    updateCellEditor();
   }
 
   /**
    * Resets the treeState instance based on the tree we're providing the look
    * and feel for. The node dimensions handler is required and must be created
    * in advance.
    */
   protected void configureLayoutCache()
   {
     treeState = createLayoutCache();
@@ -1310,59 +1327,71 @@
         mod &= ~ KeyEvent.ALT_GRAPH_DOWN_MASK;
       }
     return mod;
   }
 
   /**
    * Install all listeners for this
    */
   protected void installListeners()
   {
+    propertyChangeListener = createPropertyChangeListener();
     tree.addPropertyChangeListener(propertyChangeListener);
+
+    focusListener = createFocusListener();
     tree.addFocusListener(focusListener);
+
+    treeSelectionListener = createTreeSelectionListener();
     tree.addTreeSelectionListener(treeSelectionListener);
+
+    mouseListener = createMouseListener();
     tree.addMouseListener(mouseListener);
+
+    keyListener = createKeyListener();
     tree.addKeyListener(keyListener);
-    tree.addPropertyChangeListener(selectionModelPropertyChangeListener);
+
+    selectionModelPropertyChangeListener =
+      createSelectionModelPropertyChangeListener();
+    if (treeSelectionModel != null
+        && selectionModelPropertyChangeListener != null)
+      {
+        treeSelectionModel.addPropertyChangeListener
+                                        (selectionModelPropertyChangeListener);
+      }
+
+    componentListener = createComponentListener();
     tree.addComponentListener(componentListener);
+
+    treeExpansionListener = createTreeExpansionListener();
     tree.addTreeExpansionListener(treeExpansionListener);
+
+    treeModelListener = createTreeModelListener();
     if (treeModel != null)
       treeModel.addTreeModelListener(treeModelListener);
+
+    cellEditorListener = createCellEditorListener();
   }
 
   /**
    * Install the UI for the component
    * 
    * @param c the component to install UI for
    */
   public void installUI(JComponent c)
   {
     tree = (JTree) c;
-    treeModel = tree.getModel();
 
     prepareForUIInstall();
-    super.installUI(c);
     installDefaults();
     installComponents();
     installKeyboardActions();
     installListeners();
-
-    setCellEditor(createDefaultCellEditor());
-    createdCellEditor = true;
-    isEditing = false;
-
-    setModel(tree.getModel());
-    treeSelectionModel = tree.getSelectionModel();
-    setRootVisible(tree.isRootVisible());
-    treeState.setRootVisible(tree.isRootVisible());
-    updateExpandedDescendants(new TreePath(new Object[] { treeModel.getRoot() }));
-
     completeUIInstall();
   }
   
   /**
    * Uninstall the defaults for the tree
    */
   protected void uninstallDefaults()
   {
     tree.setFont(null);
     tree.setForeground(null);
@@ -1606,20 +1635,23 @@
    * cancelEditing. If messageTree is true, the treeModel is messaged with
    * valueForPathChanged.
    * 
    * @param messageStop message to stop editing
    * @param messageCancel message to cancel editing
    * @param messageTree message to treeModel
    */
   protected void completeEditing(boolean messageStop, boolean messageCancel,
                                  boolean messageTree)
   {
+    if (! stopEditingInCompleteEditing || editingComponent == null)
+      return;
+
     if (messageStop)
       {
         getCellEditor().stopCellEditing();
         stopEditingInCompleteEditing = true;
       }
 
     if (messageCancel)
       {
         getCellEditor().cancelCellEditing();
         stopEditingInCompleteEditing = true;
@@ -1691,49 +1723,50 @@
    * collapse region of the row, this will toggle the row.
    * 
    * @param path the path we are concerned with
    * @param mouseX is the cursor's x position
    * @param mouseY is the cursor's y position
    */
   protected void checkForClickInExpandControl(TreePath path, int mouseX,
                                               int mouseY)
   {
     if (isLocationInExpandControl(path, mouseX, mouseY))
-      toggleExpandState(path);
+      handleExpandControlClick(path, mouseX, mouseY);
   }
 
   /**
    * Returns true if the <code>mouseX</code> and <code>mouseY</code> fall in
    * the area of row that is used to expand/collpse the node and the node at row
    * does not represent a leaf.
    * 
    * @param path the path we are concerned with
    * @param mouseX is the cursor's x position
    * @param mouseY is the cursor's y position
    * @return true if the <code>mouseX</code> and <code>mouseY</code> fall in
    *         the area of row that is used to expand/collpse the node and the
    *         node at row does not represent a leaf.
    */
   protected boolean isLocationInExpandControl(TreePath path, int mouseX,
                                               int mouseY)
   {
     boolean cntlClick = false;
-    int row = getRowForPath(tree, path);
-
-    if (! isLeaf(row))
+    if (! treeModel.isLeaf(path.getLastPathComponent()))
       {
-        Rectangle bounds = getPathBounds(tree, path);
-
-        if (hasControlIcons()
-            && (mouseX < bounds.x)
-            && (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap)))
-          cntlClick = true;
+        int width = 8; // Only guessing.
+        Icon expandedIcon = getExpandedIcon();
+        if (expandedIcon != null)
+          width = expandedIcon.getIconWidth();
+
+        Insets i = tree.getInsets();
+        int left = getRowX(tree.getRowForPath(path), path.getPathCount() - 1)
+                   -getRightChildIndent() - width / 2 + i.left;
+        cntlClick = mouseX >= left && mouseX <= left + width;
       }
     return cntlClick;
   }
 
   /**
    * Messaged when the user clicks the particular row, this invokes
    * toggleExpandState.
    * 
    * @param path the path we are concerned with
    * @param mouseX is the cursor's x position
@@ -2196,108 +2229,43 @@
       // Nothing to do here.
     }
 
     /**
      * Invoked when a mouse button has been pressed on a component.
      * 
      * @param e is the mouse event that occured
      */
     public void mousePressed(MouseEvent e)
     {
-      // Any mouse click cancels the previous waiting edit action, initiated
-      // by the single click on the selected node.
-      if (startEditTimer != null)
-        {
-          startEditTimer.stop();
-          startEditTimer = null;
-        }
-
-      Point click = e.getPoint();
-      TreePath path = getClosestPathForLocation(tree, click.x, click.y);
 
-      if (path != null)
+      if (tree != null && tree.isEnabled())
         {
-          Rectangle bounds = getPathBounds(tree, path);
-          int row = getRowForPath(tree, path);
-          
-          // Cancel the editing session if clicked on the different row.
-          if (tree.isEditing() && row != editingRow)
-            cancelEditing(tree);
-          
-          boolean cntlClick = isLocationInExpandControl(path, click.x, click.y);
-
-          boolean isLeaf = isLeaf(row);
-
-          TreeCellRenderer tcr = getCellRenderer();
-          Icon icon;
-          if (isLeaf)
-            icon = UIManager.getIcon("Tree.leafIcon");
-          else if (tree.isExpanded(path))
-            icon = UIManager.getIcon("Tree.openIcon");
-          else
-            icon = UIManager.getIcon("Tree.closedIcon");
-
-          if (tcr instanceof DefaultTreeCellRenderer)
-            {
-              Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon();
-              if (tmp != null)
-                icon = tmp;
-            }
+          // Maybe stop editing and return.
+          if (isEditing(tree) && tree.getInvokesStopCellEditing()
+              && !stopEditing(tree))
+            return;
 
-          // add gap*2 for the space before and after the text
-          if (icon != null)
-            bounds.width += icon.getIconWidth() + gap * 2;
+          int x = e.getX();
+          int y = e.getY();
+          TreePath path = getClosestPathForLocation(tree, x, y);
 
-          boolean inBounds = bounds.contains(click.x, click.y);
-          if ((inBounds || cntlClick) && tree.isVisible(path))
+          if (path != null)
             {
-              if (inBounds)
-                {
-                  TreePath currentLead = tree.getLeadSelectionPath();
-                  if (currentLead != null && currentLead.equals(path)
-                      && e.getClickCount() == 1 && tree.isEditable())
-                    {
-                      // Schedule the editing session.
-                      final TreePath editPath = path;
-
-                      if (startEditTimer != null)
-                        startEditTimer.stop();
-
-                      startEditTimer = new Timer(WAIT_TILL_EDITING,
-                        new ActionListener()
-                          {
-                            public void actionPerformed(ActionEvent e)
-                              {
-                                startEditing(editPath, EDIT);
-                              }
-                          });
-                      startEditTimer.setRepeats(false);
-                      startEditTimer.start();
-                    }
-                  else
-                    {
-                      if (e.getClickCount() == 2 && ! isLeaf(row))
-                        toggleExpandState(path);
-                      else
-                        selectPathForEvent(path, e);
-                    }
-                }
+              Rectangle bounds = getPathBounds(tree, path);
+              if (SwingUtilities.isLeftMouseButton(e))
+                checkForClickInExpandControl(path, x, y);
 
-              if (cntlClick)
+              if (x > bounds.x && x <= (bounds.x + bounds.width))
                 {
-                  handleExpandControlClick(path, click.x, click.y);
-                  if (cellEditor != null)
-                    cellEditor.cancelCellEditing();
-                  tree.scrollPathToVisible(path);
+                  if (! startEditing(path, e))
+                    selectPathForEvent(path, e);
                 }
-              else if (tree.isEditable())
-                startEditing(path, e);
             }
         }
     }
 
     /**
      * Invoked when a mouse button is pressed on a component and then dragged.
      * MOUSE_DRAGGED events will continue to be delivered to the component where
      * the drag originated until the mouse button is released (regardless of
      * whether the mouse position is within the bounds of the component).
      * 
@@ -2548,22 +2516,28 @@
           treeState.setRootVisible(tree.isRootVisible());
           tree.repaint();
         }
       else if (property.equals(JTree.SELECTION_MODEL_PROPERTY))
         {
           treeSelectionModel = tree.getSelectionModel();
           treeSelectionModel.setRowMapper(treeState);
         }
       else if (property.equals(JTree.TREE_MODEL_PROPERTY))
         {
-          treeModel = tree.getModel();
-          treeModel.addTreeModelListener(treeModelListener);
+          setModel(tree.getModel());
+        }
+      else if (property.equals(JTree.CELL_RENDERER_PROPERTY))
+        {
+          setCellRenderer(tree.getCellRenderer());
+          // Update layout.
+          if (treeState != null)
+            treeState.invalidateSizes();
         }
     }
   }
 
   /**
    * Listener on the TreeSelectionModel, resets the row selection if any of the
    * properties of the model change.
    */
   public class SelectionModelPropertyChangeHandler
       implements PropertyChangeListener
Index: javax/swing/tree/DefaultTreeCellEditor.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/tree/DefaultTreeCellEditor.java,v
retrieving revision 1.21
diff -u -1 -0 -r1.21 DefaultTreeCellEditor.java
--- javax/swing/tree/DefaultTreeCellEditor.java	20 Apr 2006 11:57:47 -0000	1.21
+++ javax/swing/tree/DefaultTreeCellEditor.java	7 Jun 2006 14:34:02 -0000
@@ -375,21 +375,20 @@
     else
       editor.addCellEditorListener(new RealEditorListener());
     
     realEditor = editor;
     
     lastPath = tree.getLeadSelectionPath();
     tree.addTreeSelectionListener(this);
     editingContainer = createContainer();
     setFont(UIManager.getFont("Tree.font"));
     setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));
-    editingIcon = renderer.getIcon();
   }
 
   /**
    * Configures the editing component whenever it is null.
    * 
    * @param tree the tree to configure to component for.
    * @param renderer the renderer used to set up the nodes
    * @param editor the editor used 
    */
   private void configureEditingComponent(JTree tree,
Index: javax/swing/tree/TreePath.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/tree/TreePath.java,v
retrieving revision 1.11
diff -u -1 -0 -r1.11 TreePath.java
--- javax/swing/tree/TreePath.java	27 Apr 2006 08:23:45 -0000	1.11
+++ javax/swing/tree/TreePath.java	7 Jun 2006 14:34:02 -0000
@@ -255,28 +255,30 @@
    * @param path  the path to check (<code>null</code> permitted).
    * 
    * @return <code>true</code> if <code>path</code> is a descendant of this
    *         path, and <code>false</code> otherwise
    */
   public boolean isDescendant(TreePath path)
   {
     if (path == null)
       return false;
     int count = getPathCount();
-    if (path.getPathCount() < count)
+    int otherPathLength = path.getPathCount();
+    if (otherPathLength < count)
       return false;
-    for (int i = 0; i < count; i++)
-    {
-      if (!this.path[i].equals(path.getPathComponent(i)))
-        return false;
-    }
-    return true;
+    while (otherPathLength > count)
+      {
+        otherPathLength--;
+        path = path.getParentPath();
+      }
+    
+    return equals(path);
   }
 
   /**
    * Creates a new path that is equivalent to this path plus the specified
    * element.
    * 
    * @param element  the element.
    * 
    * @return A tree path.
    */
Index: javax/swing/tree/VariableHeightLayoutCache.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/tree/VariableHeightLayoutCache.java,v
retrieving revision 1.15
diff -u -1 -0 -r1.15 VariableHeightLayoutCache.java
--- javax/swing/tree/VariableHeightLayoutCache.java	23 May 2006 16:01:38 -0000	1.15
+++ javax/swing/tree/VariableHeightLayoutCache.java	7 Jun 2006 14:34:02 -0000
@@ -225,20 +225,23 @@
   /**
    * Refresh the row map.
    */
   private final void update()
   {
     nodes.clear();
     row2node.clear();
     
     totalHeight = maximalWidth = 0;
 
+    if (treeModel == null)
+      return;
+
     Object root = treeModel.getRoot();
 
     if (rootVisible)
       {
         countRows(root, null, 0);
       }
     else
       {
         int sc = treeModel.getChildCount(root);
         for (int i = 0; i < sc; i++)
@@ -548,23 +551,30 @@
   {
     dirty = true;
   } 
   
   /**
    * Set the tree model that will provide the data.
    */
   public void setModel(TreeModel newModel)
   {
     treeModel = newModel;
-    // The root node is expanded by default.
-    expanded.add(treeModel.getRoot());
-    dirty = true;
+    // We need to clear the table and update the layout,
+    // so that we don't end up with wrong data in the tables.
+    expanded.clear();
+    update();
+    if (treeModel != null)
+      {
+        // The root node is expanded by default.
+        expanded.add(treeModel.getRoot());
+        dirty = true;
+      }
   }
   
   /**
    * Inform the instance if the tree root node is visible. If this method
    * is not called, it is assumed that the tree root node is not visible.
    * 
    * @param visible true if the tree root node is visible, false
    * otherwise.
    */
   public void setRootVisible(boolean visible)

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil

Reply via email to