Hi,

We continue (but don't conclude) the JTree memory leak story...

This commit implements a temporary fix for the memory leak, as well as a
patch from Roman that starts fixing the root problem (however our
javax.swing.tree.DefaultTreeModel isn't firing events properly yet).

Cheers,
Francis


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

        * javax/swing/JTree.java
        (TreeModelHandler.treeNodesRemoved): Implemented.
        (TreeModelHandler.treeStructureChanged): Implemented.
        (nodeStates): Made package private.

2006-11-06  Francis Kung  <[EMAIL PROTECTED]>

        * javax/swing/JTree.java
        (clearSelectionPathStates): New private method to clean up nodeStates.
        (removeSelectionPath): Call clearSelectionPathStates().
        (removeSelectionPaths): Call clearSelectionPathStates().
        (removeSelectionRow): Call clearSelectionPathStates().
        (setSelectionPath): Call clearSelectionPathStates().
        (setSelectionPaths): Call clearSelectionPathStates().
        (setSelectionRow): Call clearSelectionPathStates().

Index: javax/swing/JTree.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTree.java,v
retrieving revision 1.77
diff -u -r1.77 JTree.java
--- javax/swing/JTree.java	18 Oct 2006 18:46:25 -0000	1.77
+++ javax/swing/JTree.java	6 Nov 2006 16:34:25 -0000
@@ -1230,8 +1230,32 @@
 	 */
     public void treeNodesRemoved(TreeModelEvent ev)
     {
-      // TODO: The API docs suggest that this method should do something
-      // but I cannot really see what has to be done here ...
+      if (ev != null)
+        {
+          TreePath parent = ev.getTreePath();
+          Object[] children = ev.getChildren();
+          TreeSelectionModel sm = getSelectionModel();
+          if (children != null)
+            {
+              TreePath path;
+              Vector toRemove = new Vector();
+              // Collect items that we must remove.
+              for (int i = children.length - 1; i >= 0; i--)
+                {
+                  path = parent.pathByAddingChild(children[i]);
+                  if (nodeStates.containsKey(path))
+                    toRemove.add(path);
+                  // Clear selection while we are at it.
+                  if (sm != null)
+                    removeDescendantSelectedPaths(path, true);
+                }
+              if (toRemove.size() > 0)
+                removeDescendantToggledPaths(toRemove.elements());
+              TreeModel model = getModel();
+              if (model == null || model.isLeaf(parent.getLastPathComponent()))
+                nodeStates.remove(parent);
+            }
+        }
     }
 
     /**
@@ -1243,9 +1267,38 @@
      */
     public void treeStructureChanged(TreeModelEvent ev)
     {
-      // Set state of new path.
-      TreePath path = ev.getTreePath();
-      setExpandedState(path, isExpanded(path));
+      if (ev != null)
+        {
+          TreePath parent = ev.getTreePath();
+          if (parent != null)
+            {
+              if (parent.getPathCount() == 1)
+                {
+                  // We have a new root, clear everything.
+                  clearToggledPaths();
+                  Object root = treeModel.getRoot();
+                  if (root != null && treeModel.isLeaf(root))
+                    nodeStates.put(parent, Boolean.TRUE);
+                }
+              else if (nodeStates.containsKey(parent))
+                {
+                  Vector toRemove = new Vector();
+                  boolean expanded = isExpanded(parent);
+                  toRemove.add(parent);
+                  removeDescendantToggledPaths(toRemove.elements());
+                  if (expanded)
+                    {
+                      TreeModel model = getModel();
+                      if (model != null
+                          || model.isLeaf(parent.getLastPathComponent()))
+                        collapsePath(parent);
+                      else
+                        nodeStates.put(parent, Boolean.TRUE);
+                    }
+                }
+              removeDescendantSelectedPaths(parent, false);
+            }
+        }
     }
   }
 
@@ -1399,8 +1452,10 @@
    * This contains the state of all nodes in the tree. Al/ entries map the
    * TreePath of a note to to its state. Valid states are EXPANDED and
    * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED.
+   *
+   * This is package private to avoid accessor methods.
    */
-  private Hashtable nodeStates = new Hashtable();
+  Hashtable nodeStates = new Hashtable();
 
   protected transient TreeCellEditor cellEditor;
 
@@ -2201,20 +2256,35 @@
 
   public void setSelectionPath(TreePath path)
   {
+    clearSelectionPathStates();
     selectionModel.setSelectionPath(path);
   }
 
   public void setSelectionPaths(TreePath[] paths)
   {
+    clearSelectionPathStates();
     selectionModel.setSelectionPaths(paths);
   }
+  
+  /**
+   * This method, and all calls to it, should be removed once the
+   * DefaultTreeModel fires events properly.  Maintenance of the nodeStates
+   * table should really be done in the TreeModelHandler.  
+   */
+  private void clearSelectionPathStates()
+  {
+    TreePath[] oldPaths = selectionModel.getSelectionPaths();
+    if (oldPaths != null)
+      for (int i = 0; i < oldPaths.length; i++)
+        nodeStates.remove(oldPaths[i]);
+  }
 
   public void setSelectionRow(int row)
   {
     TreePath path = getPathForRow(row);
 
     if (path != null)
-      selectionModel.setSelectionPath(path);
+      setSelectionPath(path);
   }
 
   public void setSelectionRows(int[] rows)
@@ -2289,11 +2359,13 @@
 
   public void removeSelectionPath(TreePath path)
   {
+    clearSelectionPathStates();
     selectionModel.removeSelectionPath(path);
   }
 
   public void removeSelectionPaths(TreePath[] paths)
   {
+    clearSelectionPathStates();
     selectionModel.removeSelectionPaths(paths);
   }
 
@@ -2302,7 +2374,7 @@
     TreePath path = getPathForRow(row);
 
     if (path != null)
-      selectionModel.removeSelectionPath(path);
+      removeSelectionPath(path);
   }
 
   public void removeSelectionRows(int[] rows)

Reply via email to