Skip to content

Commit 02756a8

Browse files
author
Marius Hanl
committed
8359599: Calling refresh() for all virtualized controls recreates all cells instead of refreshing the cells
Reviewed-by: angorya, kcr, jhendrikx, jvos
1 parent 11cff5d commit 02756a8

File tree

15 files changed

+392
-65
lines changed

15 files changed

+392
-65
lines changed

modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/Properties.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ public static String getColorPickerString(String key) {
8282

8383
/***************************************************************************
8484
*
85-
* ListView, TableView
85+
* Virtualized controls
8686
*
8787
**************************************************************************/
8888

89-
public static final String REFRESH = "refreshKey";
9089
public static final String RECREATE = "recreateKey";
90+
public static final String REBUILD = "rebuildKey";
9191

9292

9393

modules/javafx.controls/src/main/java/javafx/scene/control/ListView.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,16 +1032,14 @@ public final ObjectProperty<EventHandler<ScrollToEvent<Integer>>> onScrollToProp
10321032
}
10331033

10341034
/**
1035-
* Calling {@code refresh()} forces the ListView control to recreate and
1036-
* repopulate the cells necessary to populate the visual bounds of the control.
1037-
* In other words, this forces the ListView to update what it is showing to
1038-
* the user. This is useful in cases where the underlying data source has
1039-
* changed in a way that is not observed by the ListView itself.
1035+
* Forces the ListView to update what it is showing to the user.
1036+
* This is useful in cases where the underlying data source has changed in a way
1037+
* that is not observed by the ListView itself.
10401038
*
10411039
* @since JavaFX 8u60
10421040
*/
10431041
public void refresh() {
1044-
getProperties().put(Properties.RECREATE, Boolean.TRUE);
1042+
getProperties().put(Properties.REBUILD, Boolean.TRUE);
10451043
}
10461044

10471045

modules/javafx.controls/src/main/java/javafx/scene/control/TableView.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,16 +1763,14 @@ public void sort() {
17631763
}
17641764

17651765
/**
1766-
* Calling {@code refresh()} forces the TableView control to recreate and
1767-
* repopulate the cells necessary to populate the visual bounds of the control.
1768-
* In other words, this forces the TableView to update what it is showing to
1769-
* the user. This is useful in cases where the underlying data source has
1770-
* changed in a way that is not observed by the TableView itself.
1766+
* Forces the TableView to update what it is showing to the user.
1767+
* This is useful in cases where the underlying data source has changed in a way
1768+
* that is not observed by the TableView itself.
17711769
*
17721770
* @since JavaFX 8u60
17731771
*/
17741772
public void refresh() {
1775-
getProperties().put(Properties.RECREATE, Boolean.TRUE);
1773+
getProperties().put(Properties.REBUILD, Boolean.TRUE);
17761774
}
17771775

17781776

modules/javafx.controls/src/main/java/javafx/scene/control/TreeTableView.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,16 +2079,14 @@ public void sort() {
20792079
}
20802080

20812081
/**
2082-
* Calling {@code refresh()} forces the TreeTableView control to recreate and
2083-
* repopulate the cells necessary to populate the visual bounds of the control.
2084-
* In other words, this forces the TreeTableView to update what it is showing to
2085-
* the user. This is useful in cases where the underlying data source has
2086-
* changed in a way that is not observed by the TreeTableView itself.
2082+
* Forces the TreeTableView to update what it is showing to the user.
2083+
* This is useful in cases where the underlying data source has changed in a way
2084+
* that is not observed by the TreeTableView itself.
20872085
*
20882086
* @since JavaFX 8u60
20892087
*/
20902088
public void refresh() {
2091-
getProperties().put(Properties.RECREATE, Boolean.TRUE);
2089+
getProperties().put(Properties.REBUILD, Boolean.TRUE);
20922090
}
20932091

20942092

modules/javafx.controls/src/main/java/javafx/scene/control/TreeView.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,16 +1109,14 @@ public int getTreeItemLevel(TreeItem<?> node) {
11091109
}
11101110

11111111
/**
1112-
* Calling {@code refresh()} forces the TreeView control to recreate and
1113-
* repopulate the cells necessary to populate the visual bounds of the control.
1114-
* In other words, this forces the TreeView to update what it is showing to
1115-
* the user. This is useful in cases where the underlying data source has
1116-
* changed in a way that is not observed by the TreeView itself.
1112+
* Forces the TreeView to update what it is showing to the user.
1113+
* This is useful in cases where the underlying data source has changed in a way
1114+
* that is not observed by the TreeView itself.
11171115
*
11181116
* @since JavaFX 8u60
11191117
*/
11201118
public void refresh() {
1121-
getProperties().put(Properties.RECREATE, Boolean.TRUE);
1119+
getProperties().put(Properties.REBUILD, Boolean.TRUE);
11221120
}
11231121

11241122

modules/javafx.controls/src/main/java/javafx/scene/control/skin/ListViewSkin.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ public class ListViewSkin<T> extends VirtualContainerBase<ListView<T>, ListCell<
101101

102102
private ObservableList<T> listViewItems;
103103

104-
private boolean needCellsRebuilt = true;
105104
private boolean needCellsReconfigured = false;
106105

107106
private int itemCount = -1;
@@ -117,10 +116,9 @@ public class ListViewSkin<T> extends VirtualContainerBase<ListView<T>, ListCell<
117116

118117
private MapChangeListener<Object, Object> propertiesMapListener = c -> {
119118
if (! c.wasAdded()) return;
120-
if (Properties.RECREATE.equals(c.getKey())) {
121-
needCellsRebuilt = true;
122-
getSkinnable().requestLayout();
123-
getSkinnable().getProperties().remove(Properties.RECREATE);
119+
if (Properties.REBUILD.equals(c.getKey())) {
120+
requestRebuildCells();
121+
getSkinnable().getProperties().remove(Properties.REBUILD);
124122
}
125123
};
126124

@@ -230,7 +228,7 @@ public ListViewSkin(final ListView<T> control) {
230228
control.itemsProperty().addListener(weakItemsChangeListener);
231229

232230
final ObservableMap<Object, Object> properties = control.getProperties();
233-
properties.remove(Properties.RECREATE);
231+
properties.remove(Properties.REBUILD);
234232
properties.addListener(weakPropertiesMapListener);
235233

236234
// Register listeners
@@ -281,13 +279,10 @@ public ListViewSkin(final ListView<T> control) {
281279
final double w, final double h) {
282280
super.layoutChildren(x, y, w, h);
283281

284-
if (needCellsRebuilt) {
285-
flow.rebuildCells();
286-
} else if (needCellsReconfigured) {
282+
if (needCellsReconfigured) {
287283
flow.reconfigureCells();
288284
}
289285

290-
needCellsRebuilt = false;
291286
needCellsReconfigured = false;
292287

293288
if (getItemCount() == 0) {

modules/javafx.controls/src/main/java/javafx/scene/control/skin/TableViewSkinBase.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ public abstract class TableViewSkinBase<M, S, C extends Control, I extends Index
152152

153153
private int visibleColCount;
154154

155-
boolean needCellsRecreated = true;
156155
boolean needCellsReconfigured = false;
157156

158157
private int itemCount = -1;
@@ -297,19 +296,18 @@ public TableViewSkinBase(final C control) {
297296
});
298297

299298
final ObservableMap<Object, Object> properties = control.getProperties();
300-
properties.remove(Properties.REFRESH);
301299
properties.remove(Properties.RECREATE);
300+
properties.remove(Properties.REBUILD);
302301
lh.addMapChangeListener(properties, (c) -> {
303302
if (!c.wasAdded()) {
304303
return;
305304
}
306-
if (Properties.REFRESH.equals(c.getKey())) {
307-
refreshView();
308-
getSkinnable().getProperties().remove(Properties.REFRESH);
309-
} else if (Properties.RECREATE.equals(c.getKey())) {
310-
needCellsRecreated = true;
311-
refreshView();
305+
if (Properties.RECREATE.equals(c.getKey())) {
306+
requestRecreateCells();
312307
getSkinnable().getProperties().remove(Properties.RECREATE);
308+
} else if (Properties.REBUILD.equals(c.getKey())) {
309+
requestRebuildCells();
310+
getSkinnable().getProperties().remove(Properties.REBUILD);
313311
}
314312
});
315313

@@ -425,13 +423,10 @@ public void dispose() {
425423

426424
super.layoutChildren(x, y, w, h);
427425

428-
if (needCellsRecreated) {
429-
flow.recreateCells();
430-
} else if (needCellsReconfigured) {
426+
if (needCellsReconfigured) {
431427
flow.reconfigureCells();
432428
}
433429

434-
needCellsRecreated = false;
435430
needCellsReconfigured = false;
436431

437432
final double baselineOffset = table.getLayoutBounds().getHeight() / 2;

modules/javafx.controls/src/main/java/javafx/scene/control/skin/TreeViewSkin.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ public class TreeViewSkin<T> extends VirtualContainerBase<TreeView<T>, TreeCell<
102102

103103
private MapChangeListener<Object, Object> propertiesMapListener = c -> {
104104
if (! c.wasAdded()) return;
105-
if (Properties.RECREATE.equals(c.getKey())) {
105+
if (Properties.REBUILD.equals(c.getKey())) {
106106
requestRebuildCells();
107-
getSkinnable().getProperties().remove(Properties.RECREATE);
107+
getSkinnable().getProperties().remove(Properties.REBUILD);
108108
}
109109
};
110110

@@ -184,7 +184,7 @@ public TreeViewSkin(final TreeView control) {
184184
flow.getHbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml);
185185

186186
final ObservableMap<Object, Object> properties = control.getProperties();
187-
properties.remove(Properties.RECREATE);
187+
properties.remove(Properties.REBUILD);
188188
properties.addListener(propertiesMapListener);
189189

190190
// init the behavior 'closures'

modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualContainerBase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,8 @@ void requestRebuildCells() {
191191
flow.rebuildCells();
192192
}
193193

194+
void requestRecreateCells() {
195+
flow.recreateCells();
196+
}
197+
194198
}

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.List;
4444
import java.util.ListIterator;
4545
import java.util.NoSuchElementException;
46+
import java.util.concurrent.atomic.AtomicInteger;
4647
import java.util.stream.Collectors;
4748
import javafx.application.Platform;
4849
import javafx.beans.binding.Bindings;
@@ -2726,6 +2727,65 @@ public void fixListViewCrash_JDK_8303680() {
27262727
// But we wan't to ensure, that the VirtualFlow "Doesn't crash" - which was the case before.
27272728
}
27282729

2730+
@Test
2731+
void testRefreshShouldNotResetCells() {
2732+
final AtomicInteger creationCounter = new AtomicInteger();
2733+
2734+
ListView<Person> listView = new ListView<>();
2735+
listView.setItems(FXCollections.observableArrayList(new Person("name")));
2736+
listView.setCellFactory(_ -> {
2737+
creationCounter.incrementAndGet();
2738+
return new ListCell<>();
2739+
});
2740+
2741+
stageLoader = new StageLoader(listView);
2742+
Toolkit.getToolkit().firePulse();
2743+
2744+
assertTrue(creationCounter.get() > 0);
2745+
creationCounter.set(0);
2746+
2747+
listView.refresh();
2748+
Toolkit.getToolkit().firePulse();
2749+
2750+
assertEquals(0, creationCounter.get());
2751+
}
2752+
2753+
@Test
2754+
void testRefreshShouldReflectChangeInCell() {
2755+
String initialName = "Initial";
2756+
Person person = new Person(initialName);
2757+
2758+
ListView<Person> listView = new ListView<>();
2759+
listView.setItems(FXCollections.observableArrayList(person));
2760+
listView.setCellFactory(_ -> new ListCell<>() {
2761+
@Override
2762+
protected void updateItem(Person item, boolean empty) {
2763+
super.updateItem(item, empty);
2764+
2765+
if (empty) {
2766+
setText(null);
2767+
} else {
2768+
setText(item.getFirstName());
2769+
}
2770+
}
2771+
});
2772+
2773+
stageLoader = new StageLoader(listView);
2774+
Toolkit.getToolkit().firePulse();
2775+
2776+
String newName = "Other Name";
2777+
person.setFirstName(newName);
2778+
2779+
IndexedCell<?> cell = VirtualFlowTestUtils.getCell(listView, 0);
2780+
assertEquals(initialName, cell.getText());
2781+
2782+
listView.refresh();
2783+
Toolkit.getToolkit().firePulse();
2784+
2785+
cell = VirtualFlowTestUtils.getCell(listView, 0);
2786+
assertEquals(newName, cell.getText());
2787+
}
2788+
27292789
private static double toViewportLength(double prefHeight) {
27302790
// it would be better to calculate this from listView but there is no API for this
27312791
return prefHeight - 2;

0 commit comments

Comments
 (0)