modules/controls/src/test/java/javafx/scene/control/skin/VirtualFlowTest.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
   1 /*
   2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.scene.control.skin;
  27 
  28 import static org.junit.Assert.assertEquals;
  29 import static org.junit.Assert.assertFalse;
  30 import static org.junit.Assert.assertNotNull;
  31 import static org.junit.Assert.assertNull;
  32 import static org.junit.Assert.assertSame;
  33 import static org.junit.Assert.assertTrue;
  34 
  35 import java.util.Iterator;
  36 import java.util.LinkedList;
  37 
  38 import javafx.beans.InvalidationListener;
  39 import javafx.event.Event;
  40 import javafx.scene.control.IndexedCell;
  41 import javafx.scene.control.SkinStub;

  42 import javafx.scene.input.ScrollEvent;
  43 
  44 import org.junit.Before;
  45 import org.junit.Ignore;
  46 import org.junit.Test;
  47 
  48 import com.sun.javafx.scene.CssFlags;
  49 import com.sun.javafx.scene.control.skin.VirtualFlow.ArrayLinkedList;
  50 import java.util.List;
  51 import javafx.util.Callback;
  52 
  53 /**
  54  * Tests for the VirtualFlow class. VirtualFlow is the guts of the ListView,
  55  * TreeView, and TableView implementations.
  56  */
  57 public class VirtualFlowTest {
  58     // The following 4 vars are used when testing the
  59     private ArrayLinkedList<CellStub> list;
  60     private CellStub a;
  61     private CellStub b;
  62     private CellStub c;
  63 
  64     // The VirtualFlow we are going to test. By default, there are 100 cells
  65     // and each cell is 100 wide and 25 tall, except for the 30th cell, which
  66     // is 200 wide and 100 tall.
  67     private VirtualFlow<IndexedCell> flow;
  68 //    private Scene scene;
  69 
  70     @Before public void setUp() {
  71         list = new ArrayLinkedList<CellStub>();
  72         a = new CellStub(flow, "A");
  73         b = new CellStub(flow, "B");
  74         c = new CellStub(flow, "C");
  75 
  76         flow = new VirtualFlow();
  77 //        flow.setManaged(false);
  78         flow.setVertical(true);
  79         flow.setCreateCell(p -> new CellStub(flow) {
  80             @Override protected double computeMinWidth(double height) { return computePrefWidth(height); }
  81             @Override protected double computeMaxWidth(double height) { return computePrefWidth(height); }
  82             @Override protected double computePrefWidth(double height) {









  83                 return flow.isVertical() ? (c.getIndex() == 29 ? 200 : 100) : (c.getIndex() == 29 ? 100 : 25);
  84             }
  85 
  86             @Override protected double computeMinHeight(double width) { return computePrefHeight(width); }
  87             @Override protected double computeMaxHeight(double width) { return computePrefHeight(width); }
  88             @Override protected double computePrefHeight(double width) {









  89                 return flow.isVertical() ? (c.getIndex() == 29 ? 100 : 25) : (c.getIndex() == 29 ? 200 : 100);
  90             }
  91         });
  92         flow.setCellCount(100);
  93         flow.resize(300, 300);
  94         pulse();
  95     }
  96 
  97     private void pulse() {
  98 //        flow.impl_processCSS(true);
  99         flow.layout();
 100     }
 101 
 102     /**
 103      * Asserts that the items in the control LinkedList and the ones in the
 104      * list are exactly the same.
 105      */
 106     private void assertMatch(List<IndexedCell> control, ArrayLinkedList<IndexedCell> list) {
 107         assertEquals("The control and list did not have the same sizes. " +
 108                      "Expected " + control.size() + " but was " + list.size(),


 738             cells.add(flow.cells.get(i));
 739         }
 740         assertMatch(cells, flow.cells); // sanity check
 741         flow.requestLayout();
 742         pulse();
 743         assertMatch(cells, flow.cells);
 744         flow.setPosition(1);
 745         pulse();
 746         cells.clear();
 747         for (int i = 0; i < flow.cells.size(); i++) {
 748             cells.add(flow.cells.get(i));
 749         }
 750         flow.requestLayout();
 751         pulse();
 752         assertMatch(cells, flow.cells);
 753     }
 754 
 755 
 756     @Test
 757     public void testCellLayout_BiasedCellAndLengthBar() {
 758         flow.setCreateCell(param -> new CellStub(flow) {
 759             @Override protected double computeMinWidth(double height) { return 0; }
 760             @Override protected double computeMaxWidth(double height) { return Double.MAX_VALUE; }
 761             @Override protected double computePrefWidth(double height) {









 762                 return 200;
 763             }
 764 
 765             @Override protected double computeMinHeight(double width) { return 0; }
 766             @Override protected double computeMaxHeight(double width) { return Double.MAX_VALUE; }
 767             @Override protected double computePrefHeight(double width) {
 768                 return getIndex() == 0 ? 100 - 5 *(Math.floorDiv((int)width - 200, 10)) : 100;









 769             }
 770         });
 771         flow.setCellCount(3);
 772         flow.recreateCells(); // This help to override layoutChildren() in flow.setCellCount()
 773         flow.getVbar().setPrefWidth(20); // Since Skins are not initialized, we set the pref width explicitly
 774         flow.requestLayout();
 775         pulse();
 776         assertEquals(300, flow.cells.get(0).getWidth(), 1e-100);
 777         assertEquals(50, flow.cells.get(0).getHeight(), 1e-100);
 778 
 779         flow.resize(200, 300);
 780 
 781         flow.requestLayout();
 782         pulse();
 783         assertEquals(200, flow.cells.get(0).getWidth(), 1e-100);
 784         assertEquals(100, flow.cells.get(0).getHeight(), 1e-100);
 785 
 786     }
 787 
 788     ////////////////////////////////////////////////////////////////////////////


 873 ////
 874 ////    }
 875 ////
 876 ////    @Test public void testCellCountChanges_RowIsAddedAfterSelectedRow() {
 877 ////
 878 ////    }
 879 
 880     ////////////////////////////////////////////////////////////////////////////
 881     //
 882     //  VirtualFlow State Changes
 883     //
 884     ////////////////////////////////////////////////////////////////////////////
 885 
 886     /**
 887      * Tests that when the createCell method changes, it results in layout
 888      */
 889     @Test public void testCreateCellFunctionChangesResultInNeedsLayoutAndNoCellsAndNoAccumCell() {
 890         assertFalse(flow.isNeedsLayout());
 891         flow.getCellLength(49); // forces accum cell to be created
 892         assertNotNull("Accum cell was null", flow.accumCell);
 893         flow.setCreateCell(p -> new CellStub(flow));
 894         assertTrue(flow.isNeedsLayout());
 895         assertNull("accumCell didn't get cleared", flow.accumCell);
 896     }
 897 
 898 
 899     ////////////////////////////////////////////////////////////////////////////
 900     //
 901     //  Tests on specific functions
 902     //
 903     ////////////////////////////////////////////////////////////////////////////
 904 
 905     @Test public void test_getCellLength() {
 906         assertEquals(100, flow.getCellCount());
 907         for (int i = 0; i < 50; i++) {
 908             if (i != 29) assertEquals(25, flow.getCellLength(i), 0.0);
 909         }
 910         flow.setVertical(false);
 911         flow.requestLayout();
 912         pulse();
 913         assertEquals(100, flow.getCellCount());
 914         for (int i = 0; i < 50; i++) {
 915             if (i != 29) assertEquals("Bad index: " + i, 25, flow.getCellLength(i), 0.0);
 916         }
 917     }
 918 
 919     /*
 920     ** if we scroll the flow by a number of LINES,
 921     ** without having done anything to select a cell
 922     ** the flow should scroll.
 923     */ 
 924     @Test public void testInitialScrollEventActuallyScrolls() {
 925         /*
 926         ** re-initialize this, as it must be the first
 927         ** interaction with the flow
 928         */
 929         flow = new VirtualFlow();
 930         flow.setVertical(true);
 931         flow.setCreateCell(p -> new CellStub(flow) {
 932             @Override protected double computeMinWidth(double height) { return computePrefWidth(height); }
 933             @Override protected double computeMaxWidth(double height) { return computePrefWidth(height); }
 934             @Override protected double computePrefWidth(double height) {









 935                 return flow.isVertical() ? (c.getIndex() == 29 ? 200 : 100) : (c.getIndex() == 29 ? 100 : 25);
 936             }
 937 
 938             @Override protected double computeMinHeight(double width) { return computePrefHeight(width); }
 939             @Override protected double computeMaxHeight(double width) { return computePrefHeight(width); }
 940             @Override protected double computePrefHeight(double width) {









 941                 return flow.isVertical() ? (c.getIndex() == 29 ? 100 : 25) : (c.getIndex() == 29 ? 200 : 100);
 942             }
 943         });
 944         
 945         flow.setCellCount(100);
 946         flow.resize(300, 300);
 947         pulse();
 948        
 949         double originalValue = flow.getPosition();
 950 
 951         Event.fireEvent(flow, 
 952               new ScrollEvent(ScrollEvent.SCROLL,
 953                           0.0, -10.0, 0.0, -10.0,
 954                           false, false, false, false, true, false,
 955                           0, 0,
 956                           0, 0,
 957                           ScrollEvent.HorizontalTextScrollUnits.NONE, 0.0,
 958                           ScrollEvent.VerticalTextScrollUnits.LINES, -1.0,
 959                           0, null));
 960 
 961         assertTrue(originalValue != flow.getPosition());
 962     }
 963 
 964     @Test
 965     public void test_RT_36507() {
 966         flow = new VirtualFlow();
 967         flow.setVertical(true);
 968         // Worst case scenario is that the cells have height = 0.
 969         // The code should prevent creating more than 100 of these zero height cells
 970         // (since viewportLength is 100).
 971         // An "INFO: index exceeds maxCellCount" message should print out.
 972         flow.setCreateCell(p -> new CellStub(flow) {
 973             @Override
 974             protected double computeMaxHeight(double width) { return 0; }



 975             @Override
 976             protected double computePrefHeight(double width) { return 0; }



 977             @Override
 978             protected double computeMinHeight(double width) { return 0; }


 979 
 980         });
 981         flow.setCellCount(10);
 982         flow.setViewportLength(100);
 983         flow.addLeadingCells(1, 0);
 984         flow.sheetChildren.addListener((InvalidationListener) (o) -> {
 985             int count = ((List) o).size();
 986             assertTrue(Integer.toString(count), count <= 100);
 987         });
 988         flow.addTrailingCells(true);
 989     }
 990 
 991     private int rt36556_instanceCount;
 992     @Test
 993     public void test_rt36556() {
 994         rt36556_instanceCount = 0;
 995         flow = new VirtualFlow();
 996         flow.setVertical(true);
 997         flow.setCreateCell(p -> {
 998             rt36556_instanceCount++;
 999             return new CellStub(flow);
1000         });
1001         flow.setCellCount(100);
1002         flow.resize(300, 300);
1003         pulse();
1004         final int cellCountAtStart = rt36556_instanceCount;
1005         flow.adjustPixels(10000);
1006         pulse();
1007         assertEquals(cellCountAtStart, rt36556_instanceCount);
1008         assertNull(flow.getVisibleCell(0));
1009         assertMinimalNumberOfCellsAreUsed(flow);
1010     }
1011 
1012     @Test
1013     public void test_rt36556_scrollto() {
1014         rt36556_instanceCount = 0;
1015         flow = new VirtualFlow();
1016         flow.setVertical(true);
1017         flow.setCreateCell(p -> {
1018             rt36556_instanceCount++;
1019             return new CellStub(flow);
1020         });
1021         flow.setCellCount(100);
1022         flow.resize(300, 300);
1023         pulse();
1024         final int cellCountAtStart = rt36556_instanceCount;
1025         flow.scrollTo(80);
1026         pulse();
1027         assertEquals(cellCountAtStart, rt36556_instanceCount);
1028         assertNull(flow.getVisibleCell(0));
1029         assertMinimalNumberOfCellsAreUsed(flow);
1030     }
1031     
1032     @Test
1033     public void test_RT39035() {
1034         flow.adjustPixels(250);
1035         pulse();
1036         flow.adjustPixels(500);
1037         pulse();
1038         assertTrue(flow.getPosition() < 1.0);
1039         assertMinimalNumberOfCellsAreUsed(flow);
1040     }
1041 
1042     @Test
1043     public void test_RT37421() {
1044         flow.setPosition(0.98);
1045         pulse();
1046         flow.adjustPixels(100);
1047         pulse();
1048         assertEquals(1.0, flow.getPosition(), 0.0);
1049         assertMinimalNumberOfCellsAreUsed(flow);
1050     }
1051 
1052     @Test
1053     public void test_RT39568() {
1054         flow.getHbar().setPrefHeight(16);
1055         flow.resize(50, flow.getHeight());
1056         flow.setPosition(1);
1057         pulse();
1058         assertTrue("The hbar should have been visible", flow.getHbar().isVisible());
1059         assertMinimalNumberOfCellsAreUsed(flow);
1060         assertEquals(flow.getViewportLength()-25.0, flow.cells.getLast().getLayoutY(), 0.0);
1061     }
1062 }
1063 
1064 class CellStub extends IndexedCell {
1065     String s;
1066     VirtualFlow flow;
   1 /*
   2  * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.control.skin;
  27 
  28 import static org.junit.Assert.assertEquals;
  29 import static org.junit.Assert.assertFalse;
  30 import static org.junit.Assert.assertNotNull;
  31 import static org.junit.Assert.assertNull;
  32 import static org.junit.Assert.assertSame;
  33 import static org.junit.Assert.assertTrue;
  34 
  35 import java.util.Iterator;
  36 import java.util.LinkedList;
  37 
  38 import javafx.beans.InvalidationListener;
  39 import javafx.event.Event;
  40 import javafx.scene.control.IndexedCell;
  41 import javafx.scene.control.SkinStub;
  42 import javafx.scene.control.skin.VirtualFlow.ArrayLinkedList;
  43 import javafx.scene.input.ScrollEvent;
  44 
  45 import org.junit.Before;
  46 import org.junit.Ignore;
  47 import org.junit.Test;
  48 


  49 import java.util.List;

  50 
  51 /**
  52  * Tests for the VirtualFlow class. VirtualFlow is the guts of the ListView,
  53  * TreeView, and TableView implementations.
  54  */
  55 public class VirtualFlowTest {
  56     // The following 4 vars are used when testing the
  57     private ArrayLinkedList<CellStub> list;
  58     private CellStub a;
  59     private CellStub b;
  60     private CellStub c;
  61 
  62     // The VirtualFlow we are going to test. By default, there are 100 cells
  63     // and each cell is 100 wide and 25 tall, except for the 30th cell, which
  64     // is 200 wide and 100 tall.
  65     private VirtualFlow<IndexedCell> flow;
  66 //    private Scene scene;
  67 
  68     @Before public void setUp() {
  69         list = new ArrayLinkedList<CellStub>();
  70         a = new CellStub(flow, "A");
  71         b = new CellStub(flow, "B");
  72         c = new CellStub(flow, "C");
  73 
  74         flow = new VirtualFlow();
  75 //        flow.setManaged(false);
  76         flow.setVertical(true);
  77         flow.setCellFactory(p -> new CellStub(flow) {
  78             @Override
  79             protected double computeMinWidth(double height) {
  80                 return computePrefWidth(height);
  81             }
  82 
  83             @Override
  84             protected double computeMaxWidth(double height) {
  85                 return computePrefWidth(height);
  86             }
  87 
  88             @Override
  89             protected double computePrefWidth(double height) {
  90                 return flow.isVertical() ? (c.getIndex() == 29 ? 200 : 100) : (c.getIndex() == 29 ? 100 : 25);
  91             }
  92 
  93             @Override
  94             protected double computeMinHeight(double width) {
  95                 return computePrefHeight(width);
  96             }
  97 
  98             @Override
  99             protected double computeMaxHeight(double width) {
 100                 return computePrefHeight(width);
 101             }
 102 
 103             @Override
 104             protected double computePrefHeight(double width) {
 105                 return flow.isVertical() ? (c.getIndex() == 29 ? 100 : 25) : (c.getIndex() == 29 ? 200 : 100);
 106             }
 107         });
 108         flow.setCellCount(100);
 109         flow.resize(300, 300);
 110         pulse();
 111     }
 112 
 113     private void pulse() {
 114 //        flow.impl_processCSS(true);
 115         flow.layout();
 116     }
 117 
 118     /**
 119      * Asserts that the items in the control LinkedList and the ones in the
 120      * list are exactly the same.
 121      */
 122     private void assertMatch(List<IndexedCell> control, ArrayLinkedList<IndexedCell> list) {
 123         assertEquals("The control and list did not have the same sizes. " +
 124                      "Expected " + control.size() + " but was " + list.size(),


 754             cells.add(flow.cells.get(i));
 755         }
 756         assertMatch(cells, flow.cells); // sanity check
 757         flow.requestLayout();
 758         pulse();
 759         assertMatch(cells, flow.cells);
 760         flow.setPosition(1);
 761         pulse();
 762         cells.clear();
 763         for (int i = 0; i < flow.cells.size(); i++) {
 764             cells.add(flow.cells.get(i));
 765         }
 766         flow.requestLayout();
 767         pulse();
 768         assertMatch(cells, flow.cells);
 769     }
 770 
 771 
 772     @Test
 773     public void testCellLayout_BiasedCellAndLengthBar() {
 774         flow.setCellFactory(param -> new CellStub(flow) {
 775             @Override
 776             protected double computeMinWidth(double height) {
 777                 return 0;
 778             }
 779 
 780             @Override
 781             protected double computeMaxWidth(double height) {
 782                 return Double.MAX_VALUE;
 783             }
 784 
 785             @Override
 786             protected double computePrefWidth(double height) {
 787                 return 200;
 788             }
 789 
 790             @Override
 791             protected double computeMinHeight(double width) {
 792                 return 0;
 793             }
 794 
 795             @Override
 796             protected double computeMaxHeight(double width) {
 797                 return Double.MAX_VALUE;
 798             }
 799 
 800             @Override
 801             protected double computePrefHeight(double width) {
 802                 return getIndex() == 0 ? 100 - 5 * (Math.floorDiv((int) width - 200, 10)) : 100;
 803             }
 804         });
 805         flow.setCellCount(3);
 806         flow.recreateCells(); // This help to override layoutChildren() in flow.setCellCount()
 807         flow.getVbar().setPrefWidth(20); // Since Skins are not initialized, we set the pref width explicitly
 808         flow.requestLayout();
 809         pulse();
 810         assertEquals(300, flow.cells.get(0).getWidth(), 1e-100);
 811         assertEquals(50, flow.cells.get(0).getHeight(), 1e-100);
 812 
 813         flow.resize(200, 300);
 814 
 815         flow.requestLayout();
 816         pulse();
 817         assertEquals(200, flow.cells.get(0).getWidth(), 1e-100);
 818         assertEquals(100, flow.cells.get(0).getHeight(), 1e-100);
 819 
 820     }
 821 
 822     ////////////////////////////////////////////////////////////////////////////


 907 ////
 908 ////    }
 909 ////
 910 ////    @Test public void testCellCountChanges_RowIsAddedAfterSelectedRow() {
 911 ////
 912 ////    }
 913 
 914     ////////////////////////////////////////////////////////////////////////////
 915     //
 916     //  VirtualFlow State Changes
 917     //
 918     ////////////////////////////////////////////////////////////////////////////
 919 
 920     /**
 921      * Tests that when the createCell method changes, it results in layout
 922      */
 923     @Test public void testCreateCellFunctionChangesResultInNeedsLayoutAndNoCellsAndNoAccumCell() {
 924         assertFalse(flow.isNeedsLayout());
 925         flow.getCellLength(49); // forces accum cell to be created
 926         assertNotNull("Accum cell was null", flow.accumCell);
 927         flow.setCellFactory(p -> new CellStub(flow));
 928         assertTrue(flow.isNeedsLayout());
 929         assertNull("accumCell didn't get cleared", flow.accumCell);
 930     }
 931 
 932 
 933     ////////////////////////////////////////////////////////////////////////////
 934     //
 935     //  Tests on specific functions
 936     //
 937     ////////////////////////////////////////////////////////////////////////////
 938 
 939     @Test public void test_getCellLength() {
 940         assertEquals(100, flow.getCellCount());
 941         for (int i = 0; i < 50; i++) {
 942             if (i != 29) assertEquals(25, flow.getCellLength(i), 0.0);
 943         }
 944         flow.setVertical(false);
 945         flow.requestLayout();
 946         pulse();
 947         assertEquals(100, flow.getCellCount());
 948         for (int i = 0; i < 50; i++) {
 949             if (i != 29) assertEquals("Bad index: " + i, 25, flow.getCellLength(i), 0.0);
 950         }
 951     }
 952 
 953     /*
 954     ** if we scroll the flow by a number of LINES,
 955     ** without having done anything to select a cell
 956     ** the flow should scroll.
 957     */ 
 958     @Test public void testInitialScrollEventActuallyScrolls() {
 959         /*
 960         ** re-initialize this, as it must be the first
 961         ** interaction with the flow
 962         */
 963         flow = new VirtualFlow();
 964         flow.setVertical(true);
 965         flow.setCellFactory(p -> new CellStub(flow) {
 966             @Override
 967             protected double computeMinWidth(double height) {
 968                 return computePrefWidth(height);
 969             }
 970 
 971             @Override
 972             protected double computeMaxWidth(double height) {
 973                 return computePrefWidth(height);
 974             }
 975 
 976             @Override
 977             protected double computePrefWidth(double height) {
 978                 return flow.isVertical() ? (c.getIndex() == 29 ? 200 : 100) : (c.getIndex() == 29 ? 100 : 25);
 979             }
 980 
 981             @Override
 982             protected double computeMinHeight(double width) {
 983                 return computePrefHeight(width);
 984             }
 985 
 986             @Override
 987             protected double computeMaxHeight(double width) {
 988                 return computePrefHeight(width);
 989             }
 990 
 991             @Override
 992             protected double computePrefHeight(double width) {
 993                 return flow.isVertical() ? (c.getIndex() == 29 ? 100 : 25) : (c.getIndex() == 29 ? 200 : 100);
 994             }
 995         });
 996         
 997         flow.setCellCount(100);
 998         flow.resize(300, 300);
 999         pulse();
1000        
1001         double originalValue = flow.getPosition();
1002 
1003         Event.fireEvent(flow, 
1004               new ScrollEvent(ScrollEvent.SCROLL,
1005                           0.0, -10.0, 0.0, -10.0,
1006                           false, false, false, false, true, false,
1007                           0, 0,
1008                           0, 0,
1009                           ScrollEvent.HorizontalTextScrollUnits.NONE, 0.0,
1010                           ScrollEvent.VerticalTextScrollUnits.LINES, -1.0,
1011                           0, null));
1012 
1013         assertTrue(originalValue != flow.getPosition());
1014     }
1015 
1016     @Test
1017     public void test_RT_36507() {
1018         flow = new VirtualFlow();
1019         flow.setVertical(true);
1020         // Worst case scenario is that the cells have height = 0.
1021         // The code should prevent creating more than 100 of these zero height cells
1022         // (since viewportLength is 100).
1023         // An "INFO: index exceeds maxCellCount" message should print out.
1024         flow.setCellFactory(p -> new CellStub(flow) {
1025             @Override
1026             protected double computeMaxHeight(double width) {
1027                 return 0;
1028             }
1029 
1030             @Override
1031             protected double computePrefHeight(double width) {
1032                 return 0;
1033             }
1034 
1035             @Override
1036             protected double computeMinHeight(double width) {
1037                 return 0;
1038             }
1039 
1040         });
1041         flow.setCellCount(10);
1042         flow.setViewportLength(100);
1043         flow.addLeadingCells(1, 0);
1044         flow.sheetChildren.addListener((InvalidationListener) (o) -> {
1045             int count = ((List) o).size();
1046             assertTrue(Integer.toString(count), count <= 100);
1047         });
1048         flow.addTrailingCells(true);
1049     }
1050 
1051     private int rt36556_instanceCount;
1052     @Test
1053     public void test_rt36556() {
1054         rt36556_instanceCount = 0;
1055         flow = new VirtualFlow();
1056         flow.setVertical(true);
1057         flow.setCellFactory(p -> {
1058             rt36556_instanceCount++;
1059             return new CellStub(flow);
1060         });
1061         flow.setCellCount(100);
1062         flow.resize(300, 300);
1063         pulse();
1064         final int cellCountAtStart = rt36556_instanceCount;
1065         flow.scrollPixels(10000);
1066         pulse();
1067         assertEquals(cellCountAtStart, rt36556_instanceCount);
1068         assertNull(flow.getVisibleCell(0));
1069         assertMinimalNumberOfCellsAreUsed(flow);
1070     }
1071 
1072     @Test
1073     public void test_rt36556_scrollto() {
1074         rt36556_instanceCount = 0;
1075         flow = new VirtualFlow();
1076         flow.setVertical(true);
1077         flow.setCellFactory(p -> {
1078             rt36556_instanceCount++;
1079             return new CellStub(flow);
1080         });
1081         flow.setCellCount(100);
1082         flow.resize(300, 300);
1083         pulse();
1084         final int cellCountAtStart = rt36556_instanceCount;
1085         flow.scrollTo(80);
1086         pulse();
1087         assertEquals(cellCountAtStart, rt36556_instanceCount);
1088         assertNull(flow.getVisibleCell(0));
1089         assertMinimalNumberOfCellsAreUsed(flow);
1090     }
1091     
1092     @Test
1093     public void test_RT39035() {
1094         flow.scrollPixels(250);
1095         pulse();
1096         flow.scrollPixels(500);
1097         pulse();
1098         assertTrue(flow.getPosition() < 1.0);
1099         assertMinimalNumberOfCellsAreUsed(flow);
1100     }
1101 
1102     @Test
1103     public void test_RT37421() {
1104         flow.setPosition(0.98);
1105         pulse();
1106         flow.scrollPixels(100);
1107         pulse();
1108         assertEquals(1.0, flow.getPosition(), 0.0);
1109         assertMinimalNumberOfCellsAreUsed(flow);
1110     }
1111 
1112     @Test
1113     public void test_RT39568() {
1114         flow.getHbar().setPrefHeight(16);
1115         flow.resize(50, flow.getHeight());
1116         flow.setPosition(1);
1117         pulse();
1118         assertTrue("The hbar should have been visible", flow.getHbar().isVisible());
1119         assertMinimalNumberOfCellsAreUsed(flow);
1120         assertEquals(flow.getViewportLength()-25.0, flow.cells.getLast().getLayoutY(), 0.0);
1121     }
1122 }
1123 
1124 class CellStub extends IndexedCell {
1125     String s;
1126     VirtualFlow flow;