changeset 1686:6ca66c53de08

RT-16523: Memory leak in ListView: listeners are not removed RT-16529: Memory Leak: event handlers of root TreeItem are not removed
author jgiles
date Fri, 24 Aug 2012 09:42:03 +1200
parents 141474e431c7
children 6c299cc567e5
files javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListViewBehavior.java javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableViewBehavior.java javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeViewBehavior.java
diffstat 3 files changed, 91 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListViewBehavior.java	Wed Aug 22 16:18:29 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListViewBehavior.java	Fri Aug 24 09:42:03 2012 +1200
@@ -61,9 +61,11 @@
 import com.sun.javafx.PlatformUtil;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WeakChangeListener;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ListChangeListener.Change;
 import javafx.collections.ObservableList;
+import javafx.collections.WeakListChangeListener;
 import javafx.scene.control.*;
 import javafx.util.Callback;
 
@@ -266,7 +268,7 @@
     
     private boolean selectionChanging = false;
     
-    private ListChangeListener<Integer> selectedIndicesListener = new ListChangeListener<Integer>() {
+    private final ListChangeListener<Integer> selectedIndicesListener = new ListChangeListener<Integer>() {
         @Override public void onChanged(ListChangeListener.Change c) {
             while (c.next()) {
                 // there are no selected items, so lets clear out the anchor
@@ -304,41 +306,55 @@
             }
         }
     };
+    
+    private final ChangeListener<ObservableList<T>> itemsListener = new ChangeListener<ObservableList<T>>() {
+        @Override public void changed(ObservableValue ov, 
+                    ObservableList oldValue, 
+                    ObservableList newValue) {
+            if (oldValue != null) {
+                oldValue.removeListener(weakItemsListListener);
+            } if (newValue != null) {
+                newValue.addListener(weakItemsListListener);
+            }
+        }
+    };
+    
+    private final ChangeListener<MultipleSelectionModel<T>> selectionModelListener = new ChangeListener<MultipleSelectionModel<T>>() {
+        @Override public void changed(
+                    ObservableValue<? extends MultipleSelectionModel<T>> observable, 
+                    MultipleSelectionModel<T> oldValue, 
+                    MultipleSelectionModel<T> newValue) {
+            if (oldValue != null) {
+                oldValue.getSelectedIndices().removeListener(weakSelectedIndicesListener);
+            }
+            if (newValue != null) {
+                newValue.getSelectedIndices().addListener(weakSelectedIndicesListener);
+            }
+        }
+    };
+    
+    private final WeakChangeListener<ObservableList<T>> weakItemsListener = 
+            new WeakChangeListener<ObservableList<T>>(itemsListener);
+    private final WeakListChangeListener<Integer> weakSelectedIndicesListener = 
+            new WeakListChangeListener<Integer>(selectedIndicesListener);
+    private final WeakListChangeListener weakItemsListListener = 
+            new WeakListChangeListener(itemsListListener);
+    private final WeakChangeListener<MultipleSelectionModel<T>> weakSelectionModelListener = 
+            new WeakChangeListener<MultipleSelectionModel<T>>(selectionModelListener);
+    
 
     public ListViewBehavior(ListView control) {
         super(control);
         
-        control.itemsProperty().addListener(new ChangeListener<ObservableList<T>>() {
-            @Override public void changed(ObservableValue ov, 
-                        ObservableList oldValue, 
-                        ObservableList newValue) {
-                if (oldValue != null) {
-                    oldValue.removeListener(itemsListListener);
-                } if (newValue != null) {
-                    newValue.addListener(itemsListListener);
-                }
-            }
-        });
+        control.itemsProperty().addListener(weakItemsListener);
         if (control.getItems() != null) {
-            control.getItems().addListener(itemsListListener);
+            control.getItems().addListener(weakItemsListListener);
         }
         
         // Fix for RT-16565
-        getControl().selectionModelProperty().addListener(new ChangeListener<MultipleSelectionModel<T>>() {
-            @Override
-            public void changed(ObservableValue<? extends MultipleSelectionModel<T>> observable, 
-                        MultipleSelectionModel<T> oldValue, 
-                        MultipleSelectionModel<T> newValue) {
-                if (oldValue != null) {
-                    oldValue.getSelectedIndices().removeListener(selectedIndicesListener);
-                }
-                if (newValue != null) {
-                    newValue.getSelectedIndices().addListener(selectedIndicesListener);
-                }
-            }
-        });
+        getControl().selectionModelProperty().addListener(weakSelectionModelListener);
         if (control.getSelectionModel() != null) {
-            control.getSelectionModel().getSelectedIndices().addListener(selectedIndicesListener);
+            control.getSelectionModel().getSelectedIndices().addListener(weakSelectedIndicesListener);
         }
     }
 
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableViewBehavior.java	Wed Aug 22 16:18:29 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableViewBehavior.java	Fri Aug 24 09:42:03 2012 +1200
@@ -59,7 +59,9 @@
 import com.sun.javafx.PlatformUtil;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WeakChangeListener;
 import javafx.collections.ListChangeListener;
+import javafx.collections.WeakListChangeListener;
 import javafx.scene.control.*;
 import javafx.util.Callback;
 
@@ -241,7 +243,7 @@
     
     private boolean selectionChanging = false;
     
-    private ListChangeListener<TablePosition> selectedCellsListener = new ListChangeListener<TablePosition>() {
+    private final ListChangeListener<TablePosition> selectedCellsListener = new ListChangeListener<TablePosition>() {
         @Override public void onChanged(ListChangeListener.Change c) {
             while (c.next()) {
                 TableView.TableViewSelectionModel sm = getControl().getSelectionModel();
@@ -286,24 +288,32 @@
             }
         }
     };
+    
+    private final ChangeListener<TableView.TableViewSelectionModel<T>> selectionModelListener = 
+            new ChangeListener<TableView.TableViewSelectionModel<T>>() {
+        @Override
+        public void changed(ObservableValue<? extends TableView.TableViewSelectionModel<T>> observable, 
+                    TableView.TableViewSelectionModel<T> oldValue, 
+                    TableView.TableViewSelectionModel<T> newValue) {
+            if (oldValue != null) {
+                oldValue.getSelectedCells().removeListener(weakSelectedCellsListener);
+            }
+            if (newValue != null) {
+                newValue.getSelectedCells().addListener(weakSelectedCellsListener);
+            }
+        }
+    };
+    
+    private final WeakListChangeListener<TablePosition> weakSelectedCellsListener = 
+            new WeakListChangeListener<TablePosition>(selectedCellsListener);
+    private final WeakChangeListener<TableView.TableViewSelectionModel<T>> weakSelectionModelListener = 
+            new WeakChangeListener<TableView.TableViewSelectionModel<T>>(selectionModelListener);
 
     public TableViewBehavior(TableView control) {
         super(control);
         
         // Fix for RT-16565
-        getControl().selectionModelProperty().addListener(new ChangeListener<TableView.TableViewSelectionModel<T>>() {
-            @Override
-            public void changed(ObservableValue<? extends TableView.TableViewSelectionModel<T>> observable, 
-                        TableView.TableViewSelectionModel<T> oldValue, 
-                        TableView.TableViewSelectionModel<T> newValue) {
-                if (oldValue != null) {
-                    oldValue.getSelectedCells().removeListener(selectedCellsListener);
-                }
-                if (newValue != null) {
-                    newValue.getSelectedCells().addListener(selectedCellsListener);
-                }
-            }
-        });
+        getControl().selectionModelProperty().addListener(weakSelectionModelListener);
         if (getControl().getSelectionModel() != null) {
             getControl().getSelectionModel().getSelectedCells().addListener(selectedCellsListener);
         }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeViewBehavior.java	Wed Aug 22 16:18:29 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeViewBehavior.java	Fri Aug 24 09:42:03 2012 +1200
@@ -40,7 +40,9 @@
 import com.sun.javafx.PlatformUtil;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WeakChangeListener;
 import javafx.collections.ListChangeListener;
+import javafx.collections.WeakListChangeListener;
 import javafx.scene.input.KeyCode;
 import javafx.util.Callback;
 
@@ -213,7 +215,7 @@
     
     private boolean selectionChanging = false;
     
-    private ListChangeListener<Integer> selectedIndicesListener = new ListChangeListener<Integer>() {
+    private final ListChangeListener<Integer> selectedIndicesListener = new ListChangeListener<Integer>() {
         @Override public void onChanged(ListChangeListener.Change c) {
             while (c.next()) {
                 // there are no selected items, so lets clear out the anchor
@@ -239,26 +241,33 @@
             }
         }
     };
+    
+    private final ChangeListener<MultipleSelectionModel<TreeItem<T>>> selectionModelListener = 
+            new ChangeListener<MultipleSelectionModel<TreeItem<T>>>() {
+        @Override public void changed(ObservableValue<? extends MultipleSelectionModel<TreeItem<T>>> observable, 
+                    MultipleSelectionModel<TreeItem<T>> oldValue, 
+                    MultipleSelectionModel<TreeItem<T>> newValue) {
+            if (oldValue != null) {
+                oldValue.getSelectedIndices().removeListener(weakSelectedIndicesListener);
+            }
+            if (newValue != null) {
+                newValue.getSelectedIndices().addListener(weakSelectedIndicesListener);
+            }
+        }
+    };
+    
+    private final WeakListChangeListener<Integer> weakSelectedIndicesListener = 
+            new WeakListChangeListener<Integer>(selectedIndicesListener);
+    private final WeakChangeListener<MultipleSelectionModel<TreeItem<T>>> weakSelectionModelListener =
+            new WeakChangeListener<MultipleSelectionModel<TreeItem<T>>>(selectionModelListener);
 
     public TreeViewBehavior(TreeView control) {
         super(control);
         
         // Fix for RT-16565
-        getControl().selectionModelProperty().addListener(new ChangeListener<MultipleSelectionModel<TreeItem<T>>>() {
-            @Override
-            public void changed(ObservableValue<? extends MultipleSelectionModel<TreeItem<T>>> observable, 
-                        MultipleSelectionModel<TreeItem<T>> oldValue, 
-                        MultipleSelectionModel<TreeItem<T>> newValue) {
-                if (oldValue != null) {
-                    oldValue.getSelectedIndices().removeListener(selectedIndicesListener);
-                }
-                if (newValue != null) {
-                    newValue.getSelectedIndices().addListener(selectedIndicesListener);
-                }
-            }
-        });
+        getControl().selectionModelProperty().addListener(weakSelectionModelListener);
         if (control.getSelectionModel() != null) {
-            control.getSelectionModel().getSelectedIndices().addListener(selectedIndicesListener);
+            control.getSelectionModel().getSelectedIndices().addListener(weakSelectedIndicesListener);
         }
     }