changeset 2217:268dc298c0c4

Early work on RT-26716: Performance of scrolling TreeView tail is much more slowly when scrolling TreeView head
author jgiles
date Thu, 10 Jan 2013 13:00:59 +1300
parents 46f0bc0917cc
children d84bb839e63e
files javafx-ui-controls/src/javafx/scene/control/TreeCell.java javafx-ui-controls/src/javafx/scene/control/TreeTableRow.java javafx-ui-controls/src/javafx/scene/control/TreeUtil.java
diffstat 3 files changed, 59 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-controls/src/javafx/scene/control/TreeCell.java	Thu Jan 10 11:05:24 2013 +1300
+++ b/javafx-ui-controls/src/javafx/scene/control/TreeCell.java	Thu Jan 10 13:00:59 2013 +1300
@@ -391,15 +391,21 @@
      *                                                                         *
      **************************************************************************/
     
+    private int index = -1;
+    private int oldIndex = -1;
+    private TreeItem<T> treeItemRef;
+    
     /** {@inheritDoc} */
     @Override void indexChanged() {
         super.indexChanged();
+        index = getIndex();
         
         // when the cell index changes, this may result in the cell
         // changing state to be selected and/or focused.
         updateItem();
         updateSelection();
         updateFocus();
+        oldIndex = index;
     }
     
     private void updateItem() {
@@ -407,23 +413,21 @@
         if (tv == null) return;
         
         // Compute whether the index for this cell is for a real item
-        boolean valid = getIndex() >=0 && getIndex() < tv.getExpandedItemCount();
+        boolean valid = index >=0 && index < tv.getExpandedItemCount();
 
         // Cause the cell to update itself
         if (valid) {
             // update the TreeCell state.
             // get the new treeItem that is about to go in to the TreeCell
-            TreeItem<T> _treeItem = tv.getTreeItem(getIndex());
+            treeItemRef = oldIndex != index ? tv.getTreeItem(index) : treeItemRef;
         
             // For the sake of RT-14279, it is important that the order of these
             // method calls is as shown below. If the order is switched, it is
             // likely that events will be fired where the item is null, even
             // though calling cell.getTreeItem().getValue() returns the value
             // as expected
-            if (_treeItem == null || ! _treeItem.equals(getTreeItem())) {
-                updateTreeItem(_treeItem);
-                updateItem(_treeItem == null ? null : _treeItem.getValue(), false);
-            }
+            updateTreeItem(treeItemRef);
+            updateItem(treeItemRef == null ? null : treeItemRef.getValue(), false);
         } else {
             updateTreeItem(null);
             updateItem(null, true);
@@ -432,20 +436,20 @@
 
     private void updateSelection() {
         if (isEmpty()) return;
-        if (getIndex() == -1 || getTreeView() == null) return;
+        if (index == -1 || getTreeView() == null) return;
         if (getTreeView().getSelectionModel() == null) return;
         
-        boolean isSelected = getTreeView().getSelectionModel().isSelected(getIndex());
+        boolean isSelected = getTreeView().getSelectionModel().isSelected(index);
         if (isSelected() == isSelected) return;
         
         updateSelected(isSelected);
     }
 
     private void updateFocus() {
-        if (getIndex() == -1 || getTreeView() == null) return;
+        if (index == -1 || getTreeView() == null) return;
         if (getTreeView().getFocusModel() == null) return;
         
-        setFocused(getTreeView().getFocusModel().isFocused(getIndex()));
+        setFocused(getTreeView().getFocusModel().isFocused(index));
     }
 
     private boolean updateEditingIndex = true;
--- a/javafx-ui-controls/src/javafx/scene/control/TreeTableRow.java	Thu Jan 10 11:05:24 2013 +1300
+++ b/javafx-ui-controls/src/javafx/scene/control/TreeTableRow.java	Thu Jan 10 13:00:59 2013 +1300
@@ -84,14 +84,17 @@
     
     private final InvalidationListener indexListener = new InvalidationListener() {
         @Override public void invalidated(Observable valueModel) {
+            index = getIndex();
+        
             // when the cell index changes, this may result in the cell
             // changing state to be selected and/or focused.
             updateItem();
             updateSelection();
             updateFocus();
+            oldIndex = index;
         }
     };
-
+    
     private final ListChangeListener selectedListener = new ListChangeListener() {
         @Override public void onChanged(ListChangeListener.Change c) {
             updateSelection();
@@ -110,9 +113,22 @@
         }
     };
     
+    private final InvalidationListener leafListener = new InvalidationListener() {
+        @Override public void invalidated(Observable valueModel) {
+            // necessary to update the disclosure node in the skin when the
+            // leaf property changes
+            TreeItem treeItem = getTreeItem();
+            if (treeItem != null) {
+                requestLayout();
+            }
+        }
+    };
+    
     private final WeakListChangeListener weakSelectedListener = new WeakListChangeListener(selectedListener);
     private final WeakInvalidationListener weakFocusedListener = new WeakInvalidationListener(focusedListener);
     private final WeakInvalidationListener weakEditingListener = new WeakInvalidationListener(editingListener);
+    private final WeakInvalidationListener weakLeafListener = new WeakInvalidationListener(leafListener);
+    
     
     
     /***************************************************************************
@@ -209,6 +225,7 @@
                 weakTreeTableViewRef = new WeakReference<TreeTableView<T>>(get());
             }
 
+            updateItem();
             requestLayout();
         }
     };
@@ -320,26 +337,30 @@
      *                                                                         *
      **************************************************************************/
     
+    private int index = -1;
+    private int oldIndex = -1;
+    private TreeItem<T> treeItemRef;
+    
     private void updateItem() {
         TreeTableView<T> tv = getTreeTableView();
         if (tv == null) return;
         
         // Compute whether the index for this cell is for a real item
-        boolean valid = getIndex() >=0 && getIndex() < tv.getExpandedItemCount();
+        boolean valid = index >=0 && index < tv.getExpandedItemCount();
 
-        // get the new treeItem that is about to go in to the TreeCell
-        TreeItem<T> treeItem = valid ? tv.getTreeItem(getIndex()) : null;
-        
         // Cause the cell to update itself
-        if (valid && treeItem != null) {
+        if (valid) {
             // update the TreeCell state.
+            // get the new treeItem that is about to go in to the TreeCell
+            treeItemRef = oldIndex != index ? tv.getTreeItem(index) : treeItemRef;
+            
             // For the sake of RT-14279, it is important that the order of these
             // method calls is as shown below. If the order is switched, it is
             // likely that events will be fired where the item is null, even
             // though calling cell.getTreeItem().getValue() returns the value
             // as expected
-            updateTreeItem(treeItem);
-            updateItem(treeItem.getValue(), false);
+            updateTreeItem(treeItemRef);
+            updateItem(treeItemRef == null ? null : treeItemRef.getValue(), false);
         } else {
             updateTreeItem(null);
             updateItem(null, true);
@@ -347,10 +368,14 @@
     }
 
     private void updateSelection() {
-        if (getIndex() == -1 || getTreeTableView() == null) return;
+        if (isEmpty()) return;
+        if (index == -1 || getTreeTableView() == null) return;
         if (getTreeTableView().getSelectionModel() == null) return;
         
-        updateSelected(getTreeTableView().getSelectionModel().isSelected(getIndex()));
+        boolean isSelected = getTreeTableView().getSelectionModel().isSelected(index);
+        if (isSelected() == isSelected) return;
+        
+        updateSelected(isSelected);
     }
 
     private void updateFocus() {
@@ -402,7 +427,14 @@
      *      for developers or designers to access this function directly.
      */
     public final void updateTreeItem(TreeItem<T> treeItem) {
+        TreeItem _treeItem = getTreeItem();
+        if (_treeItem != null) {
+            _treeItem.leafProperty().removeListener(weakLeafListener);
+        }
         setTreeItem(treeItem);
+        if (treeItem != null) {
+            treeItem.leafProperty().addListener(weakLeafListener);
+        }
     }
 
 
--- a/javafx-ui-controls/src/javafx/scene/control/TreeUtil.java	Thu Jan 10 11:05:24 2013 +1300
+++ b/javafx-ui-controls/src/javafx/scene/control/TreeUtil.java	Thu Jan 10 13:00:59 2013 +1300
@@ -68,7 +68,7 @@
         int idx = itemIndex - 1;
 
         TreeItem child;
-        for (int i = 0; i < children.size(); i++) {
+        for (int i = 0, max = children.size(); i < max; i++) {
             child = children.get(i);
             if (idx == 0) return child;
             
@@ -82,8 +82,8 @@
                 idx -= expandedChildCount;
                 continue;
             }
-            
-            TreeItem<T> result = getItem(child, idx ,treeItemCountDirty);
+
+            TreeItem<T> result = getItem(child, idx, treeItemCountDirty);
             if (result != null) return result;
             idx--;
         }