Skip to content
Snippets Groups Projects
Commit 0240b86e authored by Simon Barner's avatar Simon Barner
Browse files

Merge branch '4182' into 'master'

Improve update performance of DynamicTreeTableViewer

See merge request !164
parents 31433bed f0e0b960
Branches
Tags
1 merge request!164Improve update performance of DynamicTreeTableViewer
...@@ -3,10 +3,10 @@ DynamicListContentProvider.java 817cba44f246a361207a88ef9a4e1869215803f7 GREEN ...@@ -3,10 +3,10 @@ DynamicListContentProvider.java 817cba44f246a361207a88ef9a4e1869215803f7 GREEN
DynamicStreamContentProvider.java f46e91400609cba54793dd240be0fe2aa0d5cced GREEN DynamicStreamContentProvider.java f46e91400609cba54793dd240be0fe2aa0d5cced GREEN
DynamicTextFieldTreeTableCell.java de24117e6f785b328f1ff62383626a0b4b54e8ff GREEN DynamicTextFieldTreeTableCell.java de24117e6f785b328f1ff62383626a0b4b54e8ff GREEN
DynamicTreeContentProviderBase.java 91896b1fb5104d126544c44c1ff8c30f2a13a8d6 GREEN DynamicTreeContentProviderBase.java 91896b1fb5104d126544c44c1ff8c30f2a13a8d6 GREEN
DynamicTreeItem.java 7486071d20e896d6ca9a9101bf105caccf3656d0 GREEN DynamicTreeItem.java 7e81ea98038b5eca90df583e0268d4e8f37aaf25 GREEN
DynamicTreeItemBase.java d883066ecc181120302ca32f328538de7a45b093 GREEN DynamicTreeItemBase.java d883066ecc181120302ca32f328538de7a45b093 GREEN
DynamicTreeTableUIProviderBase.java d150a4c379cc41aab2a44a5f1643f4956332c8e3 GREEN DynamicTreeTableUIProviderBase.java d150a4c379cc41aab2a44a5f1643f4956332c8e3 GREEN
DynamicTreeTableViewer.java cb289413d15159abbcccfea87d731738905b4b28 GREEN DynamicTreeTableViewer.java 62712ba0f72b57c55256648204566ac2448b8d56 GREEN
DynamicTreeUIProviderBase.java 82d3c051213f0147f4c67ad247a08696cee73110 GREEN DynamicTreeUIProviderBase.java 82d3c051213f0147f4c67ad247a08696cee73110 GREEN
DynamicTreeViewer.java 545f1ca10b7b3cad171b294a4b447875da45c9ed GREEN DynamicTreeViewer.java 545f1ca10b7b3cad171b294a4b447875da45c9ed GREEN
DynamicTreeViewerBase.java a2013538b62d86f6a09efdf2cd78babac2072484 GREEN DynamicTreeViewerBase.java a2013538b62d86f6a09efdf2cd78babac2072484 GREEN
......
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
*******************************************************************************/ *******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview; package org.fortiss.tooling.common.ui.javafx.control.treetableview;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
...@@ -37,24 +39,59 @@ public class DynamicTreeItem<T> extends DynamicTreeItemBase<T> { ...@@ -37,24 +39,59 @@ public class DynamicTreeItem<T> extends DynamicTreeItemBase<T> {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void update() { public void update() {
// remember expanded state of children
HashMap<T, TreeItem<T>> expanded = new HashMap<>(); // This method is written so that in the common cases of deleting a child, inserting a child
for(TreeItem<T> c : getChildren()) { // and swapping two children, it only updates the affected children. Especially in these
if(c.isExpanded()) { // common cases, this is much faster than clearing and re-populating the list of children.
expanded.put(c.getValue(), c); List<TreeItem<T>> children = getChildren();
HashMap<T, Boolean> expanded = new HashMap<>();
for(TreeItem<T> child : children) {
expanded.put(child.getValue(), child.isExpanded());
}
Collection<? extends T> updatedContent =
contentProvider.getFilteredSortedChildren(getValue());
// List of values that are new since the last update
List<T> newlyAddedValues = new ArrayList<>(updatedContent);
for(TreeItem<T> child : children) {
newlyAddedValues.remove(child.getValue());
}
// Remove:
children.removeIf(ti -> !updatedContent.contains(ti.getValue()));
// Insert and Update:
// In the common cases where only new values have been inserted or values have been
// permuted, this will insert/modify only the affected values. This is faster than deleting
// all children and adding them from scratch.
int i = 0;
for(T updatedValue : updatedContent) {
DynamicTreeItem<T> child = null;
if(i < children.size()) {
if(updatedValue.equals(children.get(i).getValue())) {
// Child at position i already has the right value
child = (DynamicTreeItem<T>)children.get(i);
} else {
// There is a child at position i, but its value is incorrect
child = new DynamicTreeItem<T>(updatedValue, contentProvider);
child.setExpanded(expanded.getOrDefault(updatedValue, false));
if(newlyAddedValues.contains(updatedValue)) {
children.add(i, child);
} else {
children.set(i, child);
} }
} }
// get list of children and create tree items
getChildren().clear();
for(T element : contentProvider.getFilteredSortedChildren(getValue())) {
DynamicTreeItem<T> dti;
if(expanded.containsKey(element)) {
dti = (DynamicTreeItem<T>)expanded.get(element);
} else { } else {
dti = new DynamicTreeItem<T>(element, contentProvider); // There is no child at position i
child = new DynamicTreeItem<T>(updatedValue, contentProvider);
child.setExpanded(expanded.getOrDefault(updatedValue, false));
children.add(child);
} }
getChildren().add(dti); child.update();
dti.update(); i++;
} }
} }
......
...@@ -16,15 +16,18 @@ ...@@ -16,15 +16,18 @@
package org.fortiss.tooling.common.ui.javafx.control.treetableview; package org.fortiss.tooling.common.ui.javafx.control.treetableview;
import static java.lang.Integer.MAX_VALUE; import static java.lang.Integer.MAX_VALUE;
import static java.util.stream.Collectors.toList;
import static javafx.scene.control.cell.CheckBoxTreeTableCell.forTreeTableColumn; import static javafx.scene.control.cell.CheckBoxTreeTableCell.forTreeTableColumn;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode; import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
...@@ -139,11 +142,33 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> { ...@@ -139,11 +142,33 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> {
/** Updates the viewer content. */ /** Updates the viewer content. */
public void update() { public void update() {
// wild cast works: see constructor // wild cast works: see constructor
IDynamicItem rootItem = (IDynamicItem)view.getRoot(); DynamicTreeItemBase<T> rootItem = (DynamicTreeItemBase<T>)view.getRoot();
List<T> selectedValues = getSelectedValues();
view.getSelectionModel().clearSelection();
rootItem.update(); rootItem.update();
selectValues(rootItem, selectedValues);
view.refresh(); view.refresh();
} }
/** Returns a list of all selected values */
private List<T> getSelectedValues() {
ObservableList<TreeItem<T>> selectedItems = view.getSelectionModel().getSelectedItems();
return selectedItems.stream().map(c -> c.getValue()).collect(toList());
}
/** Selects the given values in item's subtree */
private void selectValues(TreeItem<T> item, List<T> values) {
if(values.contains(item.getValue())) {
view.getSelectionModel().select(item);
}
if(item.isExpanded()) {
for(TreeItem<T> child : item.getChildren()) {
selectValues(child, values);
}
}
}
/** Expands items up to the given level. */ /** Expands items up to the given level. */
private void expandItem(TreeItem<T> parentItem, int revealLevel) { private void expandItem(TreeItem<T> parentItem, int revealLevel) {
if(revealLevel <= 0) { if(revealLevel <= 0) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment