This path fixes problems that were observed whey hiding/showing the tree root node while the tree is displayed. It also extends the tree demo to demonstrate the root node visibility changes.

2006-04-27  Audrius Meskauskas  <[EMAIL PROTECTED]>

   * examples/gnu/classpath/examples/swing/TreeDemo.java
   (createContent): Added root visibility and selection listener demos.
   * javax/swing/JTree.java (setRootVisible): If false, unselect
   the root node, if it is selected.
   * javax/swing/plaf/basic/BasicTreeUI.java
   (TreeTraverseAction.actionPerformed): Do not select the root if it
   is not visible.
   * javax/swing/tree/DefaultTreeSelectionModel.java (removeSelectionPath,
   removeSelectionPaths): Reset lead to null if the current lead path is
   removed from selection.
   * javax/swing/tree/TreePath.java (getParentPath): Cache the parent path.
   * javax/swing/tree/FixedHeightLayoutCache.java (NodeRecord.getPath):
   Return the same path regardless is root visible or not. (update):
   Reduce the identation if the root is not visible.
   * javax/swing/tree/VariableHeightLayoutCache.java (NodeRecord.getPath):
   Return the same path regardless is root visible or not. (update):
   Reduce the identation if the root is not visible.
Index: examples/gnu/classpath/examples/swing/TreeDemo.java
===================================================================
RCS file: /sources/classpath/classpath/examples/gnu/classpath/examples/swing/TreeDemo.java,v
retrieving revision 1.3
diff -u -r1.3 TreeDemo.java
--- examples/gnu/classpath/examples/swing/TreeDemo.java	26 Apr 2006 09:03:11 -0000	1.3
+++ examples/gnu/classpath/examples/swing/TreeDemo.java	27 Apr 2006 08:13:08 -0000
@@ -48,10 +48,13 @@
 import javax.swing.JCheckBox;
 import javax.swing.JComponent;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTree;
 import javax.swing.SwingUtilities;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.DefaultTreeModel;
 import javax.swing.tree.DefaultTreeSelectionModel;
@@ -169,6 +172,7 @@
         }
       });
     
+    // Demonstration of the various selection modes
     final JCheckBox cbSingle = new JCheckBox("single selection");
     cbSingle.addActionListener(new ActionListener()
       {
@@ -182,18 +186,49 @@
             DefaultTreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
       }
       });
-
+    
+    // Demonstration of the root visibility changes
+    final JCheckBox cbRoot = new JCheckBox("root");
+    cbRoot.addActionListener(new ActionListener()
+      {
+        public void actionPerformed(ActionEvent e)
+      {
+        tree.setRootVisible(cbRoot.isSelected());
+      }
+      });
+    cbRoot.setSelected(true);
+    
+    // Demonstration of the tree selection listener.
+    final JLabel choice = new JLabel("Make a choice");
+    tree.getSelectionModel().addTreeSelectionListener(
+      new TreeSelectionListener()
+        {
+          public void valueChanged(TreeSelectionEvent event)
+          {
+            TreePath was = event.getOldLeadSelectionPath();
+            TreePath now = event.getNewLeadSelectionPath();
+            String swas = 
+              was == null ? "none":was.getLastPathComponent().toString();
+            String snow = 
+              now == null ? "none":now.getLastPathComponent().toString();
+            choice.setText("From "+swas+" to "+snow);
+          }
+        }
+      );
+    
     setLayout(new BorderLayout());
     
     JPanel p2 = new JPanel(); 
     p2.add(add);
     p2.add(cbSingle);
+    p2.add(cbRoot);
     
     tree.getSelectionModel().
       setSelectionMode(DefaultTreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
 
     add(p2, BorderLayout.NORTH);
     add(new JScrollPane(tree), BorderLayout.CENTER);
+    add(choice, BorderLayout.SOUTH);
   }
 
   public void actionPerformed(ActionEvent e) 
Index: javax/swing/JTree.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/JTree.java,v
retrieving revision 1.65
diff -u -r1.65 JTree.java
--- javax/swing/JTree.java	26 Apr 2006 12:31:07 -0000	1.65
+++ javax/swing/JTree.java	27 Apr 2006 08:13:36 -0000
@@ -1953,9 +1953,19 @@
     if (rootVisible == flag)
       return;
 
+    // If the root is currently selected, unselect it
+    if (rootVisible && !flag)
+      {
+        TreeSelectionModel model = getSelectionModel();
+        // The root is always shown in the first row
+        TreePath rootPath = getPathForRow(0);
+        model.removeSelectionPath(rootPath);
+      }
+    
     boolean oldValue = rootVisible;
     rootVisible = flag;
     firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag);
+    
   }
 
   public boolean getShowsRootHandles()
Index: javax/swing/plaf/basic/BasicTreeUI.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/plaf/basic/BasicTreeUI.java,v
retrieving revision 1.134
diff -u -r1.134 BasicTreeUI.java
--- javax/swing/plaf/basic/BasicTreeUI.java	26 Apr 2006 19:34:12 -0000	1.134
+++ javax/swing/plaf/basic/BasicTreeUI.java	27 Apr 2006 08:13:45 -0000
@@ -2470,7 +2470,7 @@
   }// NodeDimensionsHandler
 
   /**
-   * PropertyChangeListener for the tree. Updates the appropriate varaible, or
+   * PropertyChangeListener for the tree. Updates the appropriate variable, or
    * TreeState, based on what changes.
    */
   public class PropertyChangeHandler
@@ -3030,9 +3030,11 @@
           else
             {
               // If the node is not expanded (also, if it is a leaf node),
-              // we just select the parent.
+              // we just select the parent. We do not select the root if it
+              // is not visible.
               TreePath parent = current.getParentPath();
-              if (parent != null)
+              if (parent != null && 
+                  !(parent.getPathCount()==1 && !tree.isRootVisible()) )
                 tree.setSelectionPath(parent);
             }
         }
Index: javax/swing/tree/DefaultTreeSelectionModel.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/tree/DefaultTreeSelectionModel.java,v
retrieving revision 1.29
diff -u -r1.29 DefaultTreeSelectionModel.java
--- javax/swing/tree/DefaultTreeSelectionModel.java	26 Apr 2006 16:18:38 -0000	1.29
+++ javax/swing/tree/DefaultTreeSelectionModel.java	27 Apr 2006 08:13:50 -0000
@@ -442,9 +442,14 @@
                                                             - index - 1);
         selection = new TreePath[temp.length];
         System.arraycopy(temp, 0, selection, 0, temp.length);
+        
+        // If the removed path was the lead path, set the lead path to null.
+        TreePath oldLead = leadPath;
+        if (path!=null && leadPath!=null && path.equals(leadPath))
+          leadPath = null;
 
-        fireValueChanged(new TreeSelectionEvent(this, path, false, leadPath,
-                                                path));
+        fireValueChanged(new TreeSelectionEvent(this, path, false, oldLead,
+                                                leadPath));
         insureRowContinuity();
       }
   }
@@ -463,6 +468,7 @@
       {
         int index = - 1;
         TreePath v0 = null;
+        TreePath oldLead = leadPath;
         for (int i = 0; i < paths.length; i++)
           {
             v0 = paths[i];
@@ -475,6 +481,8 @@
                         index = x;
                         break;
                       }
+                    if (leadPath != null && leadPath.equals(v0))
+                      leadPath = null;
                   }
                 TreePath[] temp = new TreePath[selection.length - 1];
                 System.arraycopy(selection, 0, temp, 0, index);
@@ -484,7 +492,7 @@
                 System.arraycopy(temp, 0, selection, 0, temp.length);
 
                 fireValueChanged(new TreeSelectionEvent(this, v0, false,
-                                                        leadPath, paths[0]));
+                                                        oldLead, leadPath));
               }
           }
         insureRowContinuity();
Index: javax/swing/tree/FixedHeightLayoutCache.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/tree/FixedHeightLayoutCache.java,v
retrieving revision 1.15
diff -u -r1.15 FixedHeightLayoutCache.java
--- javax/swing/tree/FixedHeightLayoutCache.java	26 Apr 2006 19:34:12 -0000	1.15
+++ javax/swing/tree/FixedHeightLayoutCache.java	27 Apr 2006 08:13:51 -0000
@@ -121,26 +121,33 @@
      */
     TreePath getPath()
     {
-      boolean lastChild = false;
-      if (parent!=null)
+      if (path == null)
         {
-          int nc = treeModel.getChildCount(parent);
-          if (nc > 0)
+          boolean lastChild = false;
+          if (parent != null)
             {
-              int n = treeModel.getIndexOfChild(parent, node);
-              if (n == nc-1)
-                lastChild = true;
+              int nc = treeModel.getChildCount(parent);
+              if (nc > 0)
+                {
+                  int n = treeModel.getIndexOfChild(parent, node);
+                  if (n == nc - 1)
+                    lastChild = true;
+                }
             }
-        }
-      if (path == null)
-        {
+
           LinkedList lpath = new LinkedList();
           NodeRecord rp = this;
           while (rp != null)
             {
               lpath.addFirst(rp.node);
               if (rp.parent != null)
-                rp = (NodeRecord) nodes.get(rp.parent);
+                {
+                  Object parent = rp.parent;
+                  rp = (NodeRecord) nodes.get(parent);
+                  // Add the root node, even if it is not visible.
+                  if (rp == null)
+                    lpath.addFirst(parent);
+                }
               else
                 rp = null;
             }
@@ -238,7 +245,7 @@
         for (int i = 0; i < sc; i++)
           {
             Object child = treeModel.getChild(root, i);
-            countRows(child, root, 1);
+            countRows(child, root, 0);
           }
       }
     dirty = false;
Index: javax/swing/tree/TreePath.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/tree/TreePath.java,v
retrieving revision 1.10
diff -u -r1.10 TreePath.java
--- javax/swing/tree/TreePath.java	10 Apr 2006 09:06:46 -0000	1.10
+++ javax/swing/tree/TreePath.java	27 Apr 2006 08:13:51 -0000
@@ -57,6 +57,11 @@
    * assumes that the TreePath is immutable, so it is marked final here.
    */
   private final Object[] path;
+  
+  /**
+   * The parent path (to be reused).
+   */
+  private transient TreePath parentPath;
 
 
   /**
@@ -294,7 +299,12 @@
     // is what the JDK does.
     if (path.length <= 1)
       return null;
-
-    return new TreePath(this.getPath(), path.length - 1);
+    
+    // Reuse the parent path, if possible. The parent path is requested
+    // during the tree repainting, so reusing generates a lot less garbage.
+    if (parentPath == null)
+      parentPath = new TreePath(this.getPath(), path.length - 1);
+    
+    return parentPath;
   }
 }
Index: javax/swing/tree/VariableHeightLayoutCache.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/tree/VariableHeightLayoutCache.java,v
retrieving revision 1.13
diff -u -r1.13 VariableHeightLayoutCache.java
--- javax/swing/tree/VariableHeightLayoutCache.java	26 Apr 2006 19:34:12 -0000	1.13
+++ javax/swing/tree/VariableHeightLayoutCache.java	27 Apr 2006 08:13:52 -0000
@@ -115,31 +115,38 @@
     private TreePath path;
     
     /**
-     * Get the path for this node. The derived class is returned,
-     * making check for the last child of some parent easier.
+     * Get the path for this node. The derived class is returned, making check
+     * for the last child of some parent easier.
      */
     TreePath getPath()
     {
-      boolean lastChild = false;
-      if (parent!=null)
+      if (path == null)
         {
-          int nc = treeModel.getChildCount(parent);
-          if (nc > 0)
+          boolean lastChild = false;
+          if (parent != null)
             {
-              int n = treeModel.getIndexOfChild(parent, node);
-              if (n == nc-1)
-                lastChild = true;
+              int nc = treeModel.getChildCount(parent);
+              if (nc > 0)
+                {
+                  int n = treeModel.getIndexOfChild(parent, node);
+                  if (n == nc - 1)
+                    lastChild = true;
+                }
             }
-        }
-      if (path == null)
-        {
+
           LinkedList lpath = new LinkedList();
           NodeRecord rp = this;
           while (rp != null)
             {
               lpath.addFirst(rp.node);
               if (rp.parent != null)
-                rp = (NodeRecord) nodes.get(rp.parent);
+                {
+                  Object parent = rp.parent;
+                  rp = (NodeRecord) nodes.get(parent);
+                  // Add the root node, even if it is not visible.
+                  if (rp == null)
+                    lpath.addFirst(parent);
+                }
               else
                 rp = null;
             }
@@ -237,7 +244,7 @@
         for (int i = 0; i < sc; i++)
           {
             Object child = treeModel.getChild(root, i);
-            countRows(child, root, 1);
+            countRows(child, root, 0);
           }
       }
     dirty = false;

Reply via email to