On Mon, 4 Jul 2022 13:52:40 GMT, Johan Vos <j...@openjdk.org> wrote:

> In order to fix the issues reported in JDK-8089589, the VirtualFlow now uses 
> the real sizes of the elements that are displayed. This allows for a more 
> natural way of scrolling through lists that contain items of very different 
> sizes.
> The algorithm that is used, does not calculate the size of each individual 
> cell upfront, as that would be a major performance overhead (especially for 
> large lists). Instead, we estimate the total size and the size of the 
> individual cells based on the real measured size of a (growing) number of 
> cells. 
> 
> There are a number of key variables that depend on this estimated size:
> * position
> * aboluteOffset
> * currentIndex
> 
> As a consequence, when the estimated size is changing, the absoluteOffset may 
> change which may lead to a new currentIndex. If this happens during a layout 
> phase, or a "complex" operation (e.g. scroll to an item and select it), this 
> may lead to visually unexpected artifacts. While the rendering becomes more 
> "correct" when the estimated size is improving, it is more important that we 
> do not create visual confusion. 
> 
> The difficulty is that there are a large number of ways to manipulate the 
> VirtualFlow, and different entry points may have different expectations about 
> which variables should be kept constant (or only changed gradually).
> 
> In this PR, we focus on consistency in the scrollTo method, where we want to 
> keep the top-cell constant. In case the estimated size is improved during the 
> scrollTo execution, or the next layoutChildren invocation, this implies 
> keeping the result of computeCurrentIndex() constant so that after scrolling 
> to a cell and selecting it, the selected cell is indeed the one that is 
> scrolled to.
> 
> This PR contains a number of tests for this scrollTo behaviour, that should 
> also be considered as regression test in case we want to add more invariants 
> later.

The fix looks good to me, although I did leave a question about one of the 
boundary checks. This will need additional testing. Several of the 
`assertEquals` calls have the expected and actual args backwards. I also left a 
few minor formatting comments (I didn't note all of them).

modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java
 line 2321:

> 2319:      */
> 2320:     void getCellSizesInExpectedViewport(int index) {
> 2321:               double estlength = getOrCreateCellSize(index);

Minor: indentation.

modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java
 line 2323:

> 2321:               double estlength = getOrCreateCellSize(index);
> 2322:         int i = index;
> 2323:         while ((estlength < viewportLength) && (++i < getCellCount())){

Minor: need space before `{`

modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java
 line 2328:

> 2326:         if (estlength < viewportLength) {
> 2327:             int j = index;
> 2328:             while ((estlength < viewportLength) && (--j > 0)) {

Is the `> 0` intentional or should it be `>= 0`?

modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java
 line 3098:

> 3096:         estSize = estimatedSize / itemCount;
> 3097: 
> 3098:         if (keepRatio ) {

Minor: there is an extra space before the `)`

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewKeyInputTest.java
 line 1837:

> 1835:     }
> 1836: 
> 1837:     @Ignore // there is no guarantee that there will be 8 selected 
> items (can be 7 as well)

Ideally we would have an open bug ID for an `@Ignore`d test. In this case, it 
might or might not be worth filing one to fix the test.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2189:

> 2187: 
> 2188:     @Test public void testUnfixedCellScrollResize() {
> 2189:         final ObservableList<Integer> items = 
> FXCollections.observableArrayList(300,300,70,20);

Minor: add spaces after the commas.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2197:

> 2195:             public void updateItem(Integer item, boolean empty) {
> 2196:                 super.updateItem(item, empty);
> 2197:                 if (!empty && (item!=null)) {

Minor: space around the `!=`

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2212:

> 2210:             IndexedCell<Integer> cell = 
> VirtualFlowTestUtils.getCell(listView, i);
> 2211:             if ((cell != null) && (cell.getItem() == 20)) {
> 2212:                 assertEquals("Last cell doesn't end at listview end", 
> cell.getLayoutY(), viewportLength - 20,1.);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2216:

> 2214:             }
> 2215:             if ((cell != null) && (cell.getItem() == 70)) {
> 2216:                 assertEquals("Secondlast cell doesn't end properly", 
> cell.getLayoutY(), viewportLength - 20 - 70,1.);

Expected and actual args are backwards.
Minor: space after the last comma.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2224:

> 2222:         // resize cells and make sure they align after scrolling
> 2223:         ObservableList<Integer> list = 
> FXCollections.observableArrayList();
> 2224:         list.addAll(300,300,20,21);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2233:

> 2231:             IndexedCell<Integer> cell = 
> VirtualFlowTestUtils.getCell(listView, i);
> 2232:             if ((cell != null) && (cell.getItem() == 21)) {
> 2233:                 assertEquals("Last cell doesn't end at listview end", 
> cell.getLayoutY(), viewportLength - 21,1.);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2237:

> 2235:             }
> 2236:             if ((cell != null) && (cell.getItem() == 20)) {
> 2237:                 assertEquals("Secondlast cell doesn't end properly", 
> cell.getLayoutY(), viewportLength - 21 - 20,1.);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2265:

> 2263:         Toolkit.getToolkit().firePulse();
> 2264:         int cc = VirtualFlowTestUtils.getCellCount(listView);
> 2265:         assertEquals(cc, 15);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2374:

> 2372:         double viewportLength = listViewHeight - 2; // it would be 
> better to calculate this from listView but there is no API for this
> 2373: 
> 2374:         for(int height: heights) {

Minor: space after `for`

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2400:

> 2398:         assertTrue("Our cell must be visible!", 
> scrollToCell.isVisible());
> 2399: 
> 2400:         if(lastCell.isVisible() && sumOfHeights >= viewportLength) {

Minor: space after `if`

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2406:

> 2404:         if(sumOfHeights < viewportLength) {
> 2405:             // If we have less cells then space, then all cells are 
> shown, and the position of the last cell, is the sum of the height of the 
> previous cells.
> 2406:             assertEquals("Last cell should be at the bottom, if we 
> scroll to it", lastCell.getLayoutY(), sumOfHeights - lastCellSize,1.);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2410:

> 2408:         if(shouldScrollToBottom && sumOfHeights > viewportLength) {
> 2409:             // If we scroll to the bottom, then the last cell should be 
> exactly at the bottom
> 2410:             // assertEquals("", lastCell.getLayoutY(), viewportLength - 
> lastCellSize,1.);

Expected and actual args are backwards.

modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java
 line 2414:

> 2412:         if(!shouldScrollToBottom && sumOfHeights > viewportLength) {
> 2413:             // If we don't scroll to the bottom, and the cells are 
> bigger than the available space, then our cell should be at the top.
> 2414:             assertEquals("Our cell mut be at the top", 
> scrollToCell.getLayoutY(), 0,1.);

Expected and actual args are backwards.

-------------

PR: https://git.openjdk.org/jfx/pull/808

Reply via email to