1 /*
   2  * Copyright (c) 2011, 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;
  27 
  28 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains;
  29 import static org.junit.Assert.assertArrayEquals;
  30 import static org.junit.Assert.assertEquals;
  31 import static org.junit.Assert.assertFalse;
  32 import static org.junit.Assert.assertNotNull;
  33 import static org.junit.Assert.assertNull;
  34 import static org.junit.Assert.assertSame;
  35 import static org.junit.Assert.assertTrue;
  36 import static org.junit.Assert.fail;
  37 
  38 import java.util.ArrayList;
  39 import java.util.Arrays;
  40 import java.util.Collections;
  41 import java.util.List;
  42 
  43 import com.sun.javafx.scene.control.behavior.ListCellBehavior;
  44 import com.sun.javafx.scene.control.behavior.TableCellBehavior;
  45 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  46 import com.sun.javafx.scene.control.infrastructure.KeyModifier;
  47 import javafx.application.Platform;
  48 import javafx.beans.binding.Bindings;
  49 import javafx.beans.property.ObjectProperty;
  50 import javafx.beans.property.ReadOnlyBooleanWrapper;
  51 import javafx.beans.property.ReadOnlyStringWrapper;
  52 import javafx.beans.property.SimpleObjectProperty;
  53 import javafx.collections.FXCollections;
  54 import javafx.collections.ListChangeListener;
  55 import javafx.collections.ObservableList;
  56 import javafx.event.ActionEvent;
  57 import javafx.scene.Parent;
  58 import javafx.scene.Scene;
  59 import javafx.scene.control.cell.CheckBoxListCell;
  60 import javafx.scene.control.cell.ComboBoxListCell;
  61 import javafx.scene.control.cell.TextFieldListCell;
  62 import javafx.scene.control.cell.TextFieldTableCell;
  63 import javafx.scene.image.ImageView;
  64 import javafx.scene.input.KeyCode;
  65 import javafx.scene.layout.HBox;
  66 import javafx.scene.layout.VBox;
  67 import javafx.scene.paint.Color;
  68 import javafx.scene.shape.Rectangle;
  69 import javafx.util.Callback;
  70 
  71 import org.junit.Before;
  72 import org.junit.Ignore;
  73 import org.junit.Test;
  74 
  75 import com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils;
  76 import com.sun.javafx.scene.control.infrastructure.StageLoader;
  77 import com.sun.javafx.scene.control.skin.VirtualScrollBar;
  78 import com.sun.javafx.scene.control.test.Person;
  79 import com.sun.javafx.scene.control.test.RT_22463_Person;
  80 import com.sun.javafx.tk.Toolkit;
  81 
  82 public class ListViewTest {
  83     private ListView<String> listView;
  84     private MultipleSelectionModel<String> sm;
  85     private FocusModel<String> fm;
  86 
  87     @Before public void setup() {
  88         listView = new ListView<>();
  89         sm = listView.getSelectionModel();
  90         fm = listView.getFocusModel();
  91     }
  92 
  93 
  94     /*********************************************************************
  95      * Tests for the constructors                                        *
  96      ********************************************************************/
  97 
  98     @Test public void noArgConstructorSetsTheStyleClass() {
  99         assertStyleClassContains(listView, "list-view");
 100     }
 101 
 102     @Test public void noArgConstructorSetsNonNullSelectionModel() {
 103         assertNotNull(sm);
 104     }
 105 
 106     @Test public void noArgConstructorSetsNonNullItems() {
 107         assertNotNull(listView.getItems());
 108     }
 109 
 110     @Test public void noArgConstructor_selectedItemIsNull() {
 111         assertNull(sm.getSelectedItem());
 112     }
 113 
 114     @Test public void noArgConstructor_selectedIndexIsNegativeOne() {
 115         assertEquals(-1, sm.getSelectedIndex());
 116     }
 117 
 118     @Test public void singleArgConstructorSetsTheStyleClass() {
 119         final ListView<String> b2 = new ListView<>(FXCollections.observableArrayList("Hi"));
 120         assertStyleClassContains(b2, "list-view");
 121     }
 122 
 123     @Test public void singleArgConstructorSetsNonNullSelectionModel() {
 124         final ListView<String> b2 = new ListView<>(FXCollections.<String>observableArrayList("Hi"));
 125         assertNotNull(b2.getSelectionModel());
 126     }
 127 
 128     @Test public void singleArgConstructorAllowsNullItems() {
 129         final ListView<String> b2 = new ListView<String>(null);
 130         assertNull(b2.getItems());
 131     }
 132 
 133     @Test public void singleArgConstructorTakesItems() {
 134         ObservableList<String> items = FXCollections.observableArrayList("Hi");
 135         final ListView<String> b2 = new ListView<>(items);
 136         assertSame(items, b2.getItems());
 137     }
 138 
 139     @Test public void singleArgConstructor_selectedItemIsNull() {
 140         final ListView<String> b2 = new ListView<>(FXCollections.observableArrayList("Hi"));
 141         assertNull(b2.getSelectionModel().getSelectedItem());
 142     }
 143 
 144     @Test public void singleArgConstructor_selectedIndexIsNegativeOne() {
 145         final ListView<String> b2 = new ListView<>(FXCollections.observableArrayList("Hi"));
 146         assertEquals(-1, b2.getSelectionModel().getSelectedIndex());
 147     }
 148 
 149     /*********************************************************************
 150      * Tests for selection model                                         *
 151      ********************************************************************/
 152 
 153     @Test public void selectionModelCanBeNull() {
 154         listView.setSelectionModel(null);
 155         assertNull(listView.getSelectionModel());
 156     }
 157 
 158     @Test public void selectionModelCanBeBound() {
 159         MultipleSelectionModel<String> sm = new ListView.ListViewBitSetSelectionModel<String>(listView);
 160         ObjectProperty<MultipleSelectionModel<String>> other = new SimpleObjectProperty<MultipleSelectionModel<String>>(sm);
 161         listView.selectionModelProperty().bind(other);
 162         assertSame(sm, sm);
 163     }
 164 
 165     @Test public void selectionModelCanBeChanged() {
 166         MultipleSelectionModel<String> sm = new ListView.ListViewBitSetSelectionModel<String>(listView);
 167         listView.setSelectionModel(sm);
 168         assertSame(sm, sm);
 169     }
 170 
 171     @Test public void canSetSelectedItemToAnItemEvenWhenThereAreNoItems() {
 172         final String randomString = new String("I AM A CRAZY RANDOM STRING");
 173         sm.select(randomString);
 174         assertEquals(-1, sm.getSelectedIndex());
 175         assertSame(randomString, sm.getSelectedItem());
 176     }
 177 
 178     @Test public void canSetSelectedItemToAnItemNotInTheDataModel() {
 179         listView.getItems().addAll("Apple", "Orange", "Banana");
 180         final String randomString = new String("I AM A CRAZY RANDOM STRING");
 181         sm.select(randomString);
 182         assertEquals(-1, sm.getSelectedIndex());
 183         assertSame(randomString, sm.getSelectedItem());
 184     }
 185 
 186     @Test public void settingTheSelectedItemToAnItemInItemsResultsInTheCorrectSelectedIndex() {
 187         listView.getItems().addAll("Apple", "Orange", "Banana");
 188         sm.select("Orange");
 189         assertEquals(1, sm.getSelectedIndex());
 190         assertSame("Orange", sm.getSelectedItem());
 191     }
 192 
 193     @Test public void settingTheSelectedItemToANonexistantItemAndThenSettingItemsWhichContainsItResultsInCorrectSelectedIndex() {
 194         sm.select("Orange");
 195         listView.getItems().addAll("Apple", "Orange", "Banana");
 196         assertEquals(1, sm.getSelectedIndex());
 197         assertSame("Orange", sm.getSelectedItem());
 198     }
 199 
 200     @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex0() {
 201         listView.getItems().addAll("Apple", "Orange", "Banana");
 202         sm.select(0);
 203         listView.getItems().clear();
 204         assertEquals(-1, sm.getSelectedIndex());
 205         assertEquals(null, sm.getSelectedItem());
 206     }
 207 
 208     @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex2() {
 209         listView.getItems().addAll("Apple", "Orange", "Banana");
 210         sm.select(2);
 211         listView.getItems().clear();
 212         assertEquals(-1, sm.getSelectedIndex());
 213         assertEquals(null, sm.getSelectedItem());
 214     }
 215 
 216     @Test public void ensureSelectedItemRemainsAccurateWhenItemsAreCleared() {
 217         listView.getItems().addAll("Apple", "Orange", "Banana");
 218         sm.select(2);
 219         listView.getItems().clear();
 220         assertNull(sm.getSelectedItem());
 221         assertEquals(-1, sm.getSelectedIndex());
 222 
 223         listView.getItems().addAll("Kiwifruit", "Mandarin", "Pineapple");
 224         sm.select(2);
 225         assertEquals("Pineapple", sm.getSelectedItem());
 226     }
 227 
 228     @Test public void ensureSelectionShiftsDownWhenOneNewItemIsAdded() {
 229         listView.getItems().addAll("Apple", "Orange", "Banana");
 230         sm.select(1);
 231         assertEquals(1, sm.getSelectedIndex());
 232         assertEquals("Orange", sm.getSelectedItem());
 233 
 234         listView.getItems().add(0, "Kiwifruit");
 235         assertEquals(2, sm.getSelectedIndex());
 236         assertEquals("Orange", sm.getSelectedItem());
 237     }
 238 
 239     @Test public void ensureSelectionShiftsDownWhenMultipleNewItemAreAdded() {
 240         listView.getItems().addAll("Apple", "Orange", "Banana");
 241         sm.select(1);
 242         assertEquals(1, sm.getSelectedIndex());
 243         assertEquals("Orange", sm.getSelectedItem());
 244 
 245         listView.getItems().addAll(0, Arrays.asList("Kiwifruit", "Pineapple", "Mandarin"));
 246         assertEquals("Orange", sm.getSelectedItem());
 247         assertEquals(4, sm.getSelectedIndex());
 248     }
 249 
 250     @Test public void ensureSelectionShiftsUpWhenOneItemIsRemoved() {
 251         listView.getItems().addAll("Apple", "Orange", "Banana");
 252         sm.select(1);
 253         assertEquals(1, sm.getSelectedIndex());
 254         assertEquals("Orange", sm.getSelectedItem());
 255 
 256         listView.getItems().remove("Apple");
 257         assertEquals(0, sm.getSelectedIndex());
 258         assertEquals("Orange", sm.getSelectedItem());
 259     }
 260 
 261     @Test public void ensureSelectionShiftsUpWheMultipleItemsAreRemoved() {
 262         listView.getItems().addAll("Apple", "Orange", "Banana");
 263         sm.select(2);
 264         assertEquals(2, sm.getSelectedIndex());
 265         assertEquals("Banana", sm.getSelectedItem());
 266 
 267         listView.getItems().removeAll(Arrays.asList("Apple", "Orange"));
 268         assertEquals(0, sm.getSelectedIndex());
 269         assertEquals("Banana", sm.getSelectedItem());
 270     }
 271 
 272     @Test public void ensureSelectionIsCorrectWhenItemsChange() {
 273         listView.setItems(FXCollections.observableArrayList("Item 1"));
 274         sm.select(0);
 275         assertEquals("Item 1", sm.getSelectedItem());
 276 
 277         listView.setItems(FXCollections.observableArrayList("Item 2"));
 278         assertEquals(-1, sm.getSelectedIndex());
 279         assertNull(sm.getSelectedItem());
 280         assertEquals(0, fm.getFocusedIndex());
 281         assertEquals("Item 2", fm.getFocusedItem());
 282     }
 283 
 284     @Test public void test_rt15793() {
 285         // ListView selectedIndex is 0 although the items list is empty
 286         final ListView lv = new ListView();
 287         final ObservableList list = FXCollections.observableArrayList();
 288         lv.setItems(list);
 289         list.add("toto");
 290         lv.getSelectionModel().select(0);
 291         assertEquals(0, lv.getSelectionModel().getSelectedIndex());
 292         list.remove(0);
 293         assertEquals(-1, lv.getSelectionModel().getSelectedIndex());
 294     }
 295 
 296     @Test public void test_rt17522_focusShouldMoveWhenItemAddedAtFocusIndex() {
 297         final ListView lv = new ListView();
 298         FocusModel fm = lv.getFocusModel();
 299         lv.getItems().add("row1");
 300         fm.focus(0);
 301         assertTrue(fm.isFocused(0));
 302 
 303         lv.getItems().add(0, "row0");
 304         assertTrue(fm.isFocused(1));
 305     }
 306 
 307     @Test public void test_rt17522_focusShouldMoveWhenItemAddedBeforeFocusIndex() {
 308         final ListView lv = new ListView();
 309         FocusModel fm = lv.getFocusModel();
 310         lv.getItems().addAll("row1", "row2");
 311         fm.focus(1);
 312         assertTrue(fm.isFocused(1));
 313         assertEquals("row2", fm.getFocusedItem());
 314 
 315         lv.getItems().add(1, "row0");
 316         assertTrue(fm.isFocused(2));
 317         assertEquals("row2", fm.getFocusedItem());
 318         assertFalse(fm.isFocused(1));
 319     }
 320 
 321     @Test public void test_rt17522_focusShouldNotMoveWhenItemAddedAfterFocusIndex() {
 322         final ListView lv = new ListView();
 323         FocusModel fm = lv.getFocusModel();
 324         lv.getItems().addAll("row1");
 325         fm.focus(0);
 326         assertTrue(fm.isFocused(0));
 327         assertEquals("row1", fm.getFocusedItem());
 328 
 329         lv.getItems().add(1, "row2");
 330         assertTrue(fm.isFocused(0));
 331         assertEquals("row1", fm.getFocusedItem());
 332         assertFalse(fm.isFocused(1));
 333     }
 334 
 335     @Test public void test_rt17522_focusShouldBeResetWhenFocusedItemIsRemoved() {
 336         final ListView lv = new ListView();
 337         FocusModel fm = lv.getFocusModel();
 338         lv.getItems().add("row1");
 339         fm.focus(0);
 340         assertTrue(fm.isFocused(0));
 341 
 342         lv.getItems().remove("row1");
 343         assertTrue(fm.getFocusedIndex() == -1);
 344         assertNull(fm.getFocusedItem());
 345     }
 346 
 347     @Test public void test_rt17522_focusShouldMoveWhenItemRemovedBeforeFocusIndex() {
 348         final ListView lv = new ListView();
 349         FocusModel fm = lv.getFocusModel();
 350         lv.getItems().addAll("row1", "row2");
 351         fm.focus(1);
 352         assertTrue(fm.isFocused(1));
 353         assertEquals("row2", fm.getFocusedItem());
 354 
 355         lv.getItems().remove("row1");
 356         assertTrue(fm.isFocused(0));
 357         assertEquals("row2", fm.getFocusedItem());
 358     }
 359 
 360     @Test public void test_rt17522_focusShouldNotMoveWhenItemRemovedAfterFocusIndex() {
 361         final ListView lv = new ListView();
 362         FocusModel fm = lv.getFocusModel();
 363         lv.getItems().addAll("row1", "row2");
 364         fm.focus(0);
 365         assertTrue(fm.isFocused(0));
 366         assertEquals("row1", fm.getFocusedItem());
 367 
 368         lv.getItems().remove("row2");
 369         assertTrue(fm.isFocused(0));
 370         assertEquals("row1", fm.getFocusedItem());
 371     }
 372 
 373     @Test public void test_rt18385() {
 374         listView.getItems().addAll("row1", "row2", "row3");
 375         sm.select(1);
 376         listView.getItems().add("Another Row");
 377         assertEquals(1, sm.getSelectedIndices().size());
 378         assertEquals(1, sm.getSelectedItems().size());
 379     }
 380 
 381     @Test public void test_rt18339_onlyEditWhenListViewIsEditable_editableIsFalse() {
 382         listView.setEditable(false);
 383         listView.edit(1);
 384         assertEquals(-1, listView.getEditingIndex());
 385     }
 386 
 387     @Test public void test_rt18339_onlyEditWhenListViewIsEditable_editableIsTrue() {
 388         listView.setEditable(true);
 389         listView.edit(1);
 390         assertEquals(1, listView.getEditingIndex());
 391     }
 392 
 393     @Test public void test_rt14451() {
 394         listView.getItems().addAll("Apple", "Orange", "Banana");
 395         sm.setSelectionMode(SelectionMode.MULTIPLE);
 396         sm.selectRange(0, 2); // select from 0 (inclusive) to 2 (exclusive)
 397         assertEquals(2, sm.getSelectedIndices().size());
 398     }
 399 
 400     private int rt_18969_hitCount = 0;
 401     @Test public void test_rt18969() {
 402         rt_18969_hitCount = 0;
 403         ObservableList<String> emptyModel = FXCollections.observableArrayList();
 404         listView.setItems(emptyModel);
 405         assertTrue(listView.getItems().isEmpty());
 406 
 407         sm.selectedItemProperty().addListener((observable, oldValue, newValue) -> {
 408             rt_18969_hitCount++;
 409         });
 410 
 411         ObservableList<String> mod = FXCollections.observableArrayList();
 412         mod.add(System.currentTimeMillis()+"");
 413         listView.getItems().setAll(mod);
 414 
 415         sm.select(0);
 416         assertTrue(sm.isSelected(0));
 417         assertEquals(1, rt_18969_hitCount);
 418 
 419         // sleep for 100ms so that the currentTimeMillis is guaranteed to be
 420         // a different value than the first one
 421         try {
 422             Thread.sleep(100);
 423         } catch (InterruptedException ex) {
 424             ex.printStackTrace();
 425         }
 426 
 427         // the list is totally changing (it is being cleared), so we should 
 428         // be nulling out the selection model state
 429         mod = FXCollections.observableArrayList();
 430         mod.add(System.currentTimeMillis()+"");
 431         listView.getItems().setAll(mod);
 432 
 433         // it should be two, as there is no null event in between (although there
 434         // used to be, so the test used to be for three hits)
 435         assertEquals(2, rt_18969_hitCount);
 436     }
 437 
 438     @Test public void test_rt21586() {
 439         listView.getItems().setAll("Apple", "Orange", "Banana");
 440         listView.getSelectionModel().select(1);
 441         assertEquals(1, listView.getSelectionModel().getSelectedIndex());
 442         assertEquals("Orange", listView.getSelectionModel().getSelectedItem());
 443 
 444         listView.getItems().setAll("Kiwifruit", "Pineapple", "Grape");
 445         assertEquals(-1, listView.getSelectionModel().getSelectedIndex());
 446         assertNull(listView.getSelectionModel().getSelectedItem());
 447     }
 448 
 449     @Test public void test_rt27820_1() {
 450         listView.getItems().setAll("Apple", "Orange");
 451         listView.getSelectionModel().select(0);
 452         assertEquals(1, listView.getSelectionModel().getSelectedItems().size());
 453         assertEquals("Apple", listView.getSelectionModel().getSelectedItem());
 454 
 455         listView.getItems().clear();
 456         assertEquals(0, listView.getSelectionModel().getSelectedItems().size());
 457         assertNull(listView.getSelectionModel().getSelectedItem());
 458     }
 459 
 460     @Test public void test_rt27820_2() {
 461         listView.getItems().setAll("Apple", "Orange");
 462         listView.getSelectionModel().select(1);
 463         assertEquals(1, listView.getSelectionModel().getSelectedItems().size());
 464         assertEquals("Orange", listView.getSelectionModel().getSelectedItem());
 465 
 466         listView.getItems().clear();
 467         assertEquals(0, listView.getSelectionModel().getSelectedItems().size());
 468         assertNull(listView.getSelectionModel().getSelectedItem());
 469     }
 470 
 471     @Test public void test_rt28534() {
 472         ListView<Person> list = new ListView<Person>();
 473         list.setItems(FXCollections.observableArrayList(
 474                 new Person("Jacob", "Smith", "jacob.smith@example.com"),
 475                 new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
 476                 new Person("Ethan", "Williams", "ethan.williams@example.com"),
 477                 new Person("Emma", "Jones", "emma.jones@example.com"),
 478                 new Person("Michael", "Brown", "michael.brown@example.com")));
 479 
 480         VirtualFlowTestUtils.assertRowsNotEmpty(list, 0, 5); // rows 0 - 5 should be filled
 481         VirtualFlowTestUtils.assertRowsEmpty(list, 5, -1); // rows 5+ should be empty
 482 
 483         // now we replace the data and expect the cells that have no data
 484         // to be empty
 485         list.setItems(FXCollections.observableArrayList(
 486                 new Person("*_*Emma", "Jones", "emma.jones@example.com"),
 487                 new Person("_Michael", "Brown", "michael.brown@example.com")));
 488 
 489         VirtualFlowTestUtils.assertRowsNotEmpty(list, 0, 2); // rows 0 - 2 should be filled
 490         VirtualFlowTestUtils.assertRowsEmpty(list, 2, -1); // rows 2+ should be empty
 491     }
 492 
 493     @Test public void test_rt22463() {
 494         final ListView<RT_22463_Person> list = new ListView<RT_22463_Person>();
 495 
 496         // before the change things display fine
 497         RT_22463_Person p1 = new RT_22463_Person();
 498         p1.setId(1l);
 499         p1.setName("name1");
 500         RT_22463_Person p2 = new RT_22463_Person();
 501         p2.setId(2l);
 502         p2.setName("name2");
 503         list.setItems(FXCollections.observableArrayList(p1, p2));
 504         VirtualFlowTestUtils.assertCellTextEquals(list, 0, "name1");
 505         VirtualFlowTestUtils.assertCellTextEquals(list, 1, "name2");
 506 
 507         // now we change the persons but they are still equal as the ID's don't
 508         // change - but the items list is cleared so the cells should update
 509         RT_22463_Person new_p1 = new RT_22463_Person();
 510         new_p1.setId(1l);
 511         new_p1.setName("updated name1");
 512         RT_22463_Person new_p2 = new RT_22463_Person();
 513         new_p2.setId(2l);
 514         new_p2.setName("updated name2");
 515         list.getItems().clear();
 516         list.setItems(FXCollections.observableArrayList(new_p1, new_p2));
 517         VirtualFlowTestUtils.assertCellTextEquals(list, 0, "updated name1");
 518         VirtualFlowTestUtils.assertCellTextEquals(list, 1, "updated name2");
 519     }
 520 
 521     @Test public void test_rt28637() {
 522         ObservableList<String> items = FXCollections.observableArrayList("String1", "String2", "String3", "String4");
 523 
 524         final ListView<String> listView = new ListView<String>();
 525         listView.setItems(items);
 526 
 527         listView.getSelectionModel().select(0);
 528         assertEquals("String1", listView.getSelectionModel().getSelectedItem());
 529         assertEquals("String1", listView.getSelectionModel().getSelectedItems().get(0));
 530         assertEquals(0, listView.getSelectionModel().getSelectedIndex());
 531 
 532         items.remove(listView.getSelectionModel().getSelectedItem());
 533         assertEquals("String2", listView.getSelectionModel().getSelectedItem());
 534         assertEquals("String2", listView.getSelectionModel().getSelectedItems().get(0));
 535         assertEquals(0, listView.getSelectionModel().getSelectedIndex());
 536     }
 537 
 538     @Test public void test_rt28819_1() {
 539         ObservableList<String> emptyModel = FXCollections.observableArrayList();
 540 
 541         final ListView<String> listView = new ListView<String>();
 542         listView.setItems(emptyModel);
 543         VirtualFlowTestUtils.assertRowsEmpty(listView, 0, 5);
 544 
 545         ObservableList<String> mod = FXCollections.observableArrayList();
 546         String value = System.currentTimeMillis()+"";
 547         mod.add(value);
 548         listView.setItems(mod);
 549         VirtualFlowTestUtils.assertCellCount(listView, 1);
 550         VirtualFlowTestUtils.assertCellTextEquals(listView, 0, value);
 551     }
 552 
 553     @Test public void test_rt28819_2() {
 554         ObservableList<String> emptyModel = FXCollections.observableArrayList();
 555 
 556         final ListView<String> listView = new ListView<String>();
 557         listView.setItems(emptyModel);
 558         VirtualFlowTestUtils.assertRowsEmpty(listView, 0, 5);
 559 
 560         ObservableList<String> mod1 = FXCollections.observableArrayList();
 561         String value1 = System.currentTimeMillis()+"";
 562         mod1.add(value1);
 563         listView.getItems().setAll(mod1);
 564         VirtualFlowTestUtils.assertCellCount(listView, 1);
 565         VirtualFlowTestUtils.assertCellTextEquals(listView, 0, value1);
 566     }
 567 
 568     @Test public void test_rt29390() {
 569         ObservableList<String> items = FXCollections.observableArrayList(
 570                 "String1", "String2", "String3", "String4",
 571                 "String1", "String2", "String3", "String4",
 572                 "String1", "String2", "String3", "String4",
 573                 "String1", "String2", "String3", "String4"
 574         );
 575 
 576         final ListView<String> listView = new ListView<String>(items);
 577         listView.setMaxHeight(50);
 578         listView.setPrefHeight(50);
 579 
 580         // we want the vertical scrollbar
 581         VirtualScrollBar scrollBar = VirtualFlowTestUtils.getVirtualFlowVerticalScrollbar(listView);
 582 
 583         assertNotNull(scrollBar);
 584         assertTrue(scrollBar.isVisible());
 585         assertTrue(scrollBar.getVisibleAmount() > 0.0);
 586         assertTrue(scrollBar.getVisibleAmount() < 1.0);
 587 
 588         // this next test is likely to be brittle, but we'll see...If it is the
 589         // cause of failure then it can be commented out
 590         assertEquals(0.125, scrollBar.getVisibleAmount(), 0.0);
 591     }
 592 
 593     @Test public void test_rt30400() {
 594         // create a listview that'll render cells using the check box cell factory
 595         ObservableList<String> items = FXCollections.observableArrayList("String1");
 596         final ListView<String> listView = new ListView<String>(items);
 597         listView.setMinHeight(100);
 598         listView.setPrefHeight(100);
 599         listView.setCellFactory(CheckBoxListCell.forListView(param -> new ReadOnlyBooleanWrapper(true)));
 600 
 601         // because only the first row has data, all other rows should be 
 602         // empty (and not contain check boxes - we just check the first four here)
 603         VirtualFlowTestUtils.assertRowsNotEmpty(listView, 0, 1);
 604         VirtualFlowTestUtils.assertCellNotEmpty(VirtualFlowTestUtils.getCell(listView, 0));
 605         VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(listView, 1));
 606         VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(listView, 2));
 607         VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(listView, 3));
 608     }
 609 
 610     @Test public void test_rt29420() {
 611         final ListView<String> listView = new ListView<String>();
 612 
 613         VBox vbox = new VBox(listView);
 614         StageLoader sl = new StageLoader(vbox);
 615 
 616         // the initial width of a ListView should be the golden rectangle where
 617         // the height is hardcoded to be 400
 618         final double initialWidth = listView.prefWidth(-1);
 619         assertEquals(400 * 0.618033987, initialWidth, 0.00);
 620 
 621         // add in some items, and re-measure - seeing as the items are narrow,
 622         // the width shouldn't change
 623         listView.getItems().addAll("one", "two", "three", "four", "five", "six");
 624         Toolkit.getToolkit().firePulse();
 625         final double withContentWidth = listView.prefWidth(-1);
 626         assertEquals(initialWidth, withContentWidth, 0.00);
 627 
 628         // remove the items - and the width should remain the same
 629         listView.getItems().clear();
 630         Toolkit.getToolkit().firePulse();
 631         final double afterEmptiedWidth = listView.prefWidth(-1);
 632         assertEquals(initialWidth, afterEmptiedWidth, 0.00);
 633 
 634         sl.dispose();
 635     }
 636 
 637     @Test public void test_rt31165() {
 638         final ObservableList names = FXCollections.observableArrayList("Adam", "Alex", "Alfred", "Albert");
 639         final ObservableList data = FXCollections.observableArrayList();
 640         for (int i = 0; i < 18; i++) {
 641             data.add(""+i);
 642         }
 643 
 644         final ListView listView = new ListView(data);
 645         listView.setPrefSize(200, 250);
 646         listView.setEditable(true);
 647         listView.setCellFactory(ComboBoxListCell.forListView(names));
 648 
 649         IndexedCell cell = VirtualFlowTestUtils.getCell(listView, 1);
 650         assertEquals("1", cell.getText());
 651         assertFalse(cell.isEditing());
 652 
 653         listView.edit(1);
 654 
 655         assertEquals(1, listView.getEditingIndex());
 656         assertTrue(cell.isEditing());
 657 
 658         VirtualFlowTestUtils.getVirtualFlow(listView).requestLayout();
 659         Toolkit.getToolkit().firePulse();
 660 
 661         assertEquals(1, listView.getEditingIndex());
 662         assertTrue(cell.isEditing());
 663     }
 664 
 665     @Test public void test_rt31471() {
 666         final ObservableList names = FXCollections.observableArrayList("Adam", "Alex", "Alfred", "Albert");
 667         final ListView listView = new ListView(names);
 668 
 669         IndexedCell cell = VirtualFlowTestUtils.getCell(listView, 0);
 670         assertEquals("Adam", cell.getItem());
 671 
 672         listView.setFixedCellSize(50);
 673 
 674         VirtualFlowTestUtils.getVirtualFlow(listView).requestLayout();
 675         Toolkit.getToolkit().firePulse();
 676 
 677         assertEquals("Adam", cell.getItem());
 678         assertEquals(50, cell.getHeight(), 0.00);
 679     }
 680 
 681     private int rt_31200_count = 0;
 682     @Test public void test_rt_31200() {
 683         final ListView listView = new ListView();
 684         listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 685             @Override
 686             public ListCell<String> call(ListView<String> param) {
 687                 return new ListCell<String>() {
 688                     ImageView view = new ImageView();
 689                     { setGraphic(view); };
 690 
 691                     @Override
 692                     protected void updateItem(String item, boolean empty) {
 693                         if (getItem() == null ? item == null : getItem().equals(item)) {
 694                             rt_31200_count++;
 695                         }
 696                         super.updateItem(item, empty);
 697                         if (item == null || empty) {
 698                             view.setImage(null);
 699                             setText(null);
 700                         } else {
 701                             setText(item);
 702                         }
 703                     }
 704                 };
 705             }
 706         });
 707         listView.getItems().setAll("one", "two", "three", "four", "five");
 708 
 709         StageLoader sl = new StageLoader(listView);
 710 
 711         assertEquals(24, rt_31200_count);
 712 
 713         // resize the stage
 714         sl.getStage().setHeight(250);
 715         Toolkit.getToolkit().firePulse();
 716         sl.getStage().setHeight(50);
 717         Toolkit.getToolkit().firePulse();
 718         assertEquals(24, rt_31200_count);
 719 
 720         sl.dispose();
 721     }
 722 
 723     @Test public void test_rt_30484() {
 724         final ListView listView = new ListView();
 725         listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
 726             @Override public ListCell<String> call(ListView<String> param) {
 727                 return new ListCell<String>() {
 728                     Rectangle graphic = new Rectangle(10, 10, Color.RED);
 729                     { setGraphic(graphic); };
 730 
 731                     @Override protected void updateItem(String item, boolean empty) {
 732                         super.updateItem(item, empty);
 733                         if (item == null || empty) {
 734                             graphic.setVisible(false);
 735                             setText(null);
 736                         } else {
 737                             graphic.setVisible(true);
 738                             setText(item);
 739                         }
 740                     }
 741                 };
 742             }
 743         });
 744 
 745         // First two rows have content, so the graphic should show.
 746         // All other rows have no content, so graphic should not show.
 747         listView.getItems().setAll("one", "two");
 748 
 749         VirtualFlowTestUtils.assertGraphicIsVisible(listView, 0);
 750         VirtualFlowTestUtils.assertGraphicIsVisible(listView, 1);
 751         VirtualFlowTestUtils.assertGraphicIsNotVisible(listView, 2);
 752         VirtualFlowTestUtils.assertGraphicIsNotVisible(listView, 3);
 753         VirtualFlowTestUtils.assertGraphicIsNotVisible(listView, 4);
 754         VirtualFlowTestUtils.assertGraphicIsNotVisible(listView, 5);
 755     }
 756 
 757     private int rt_29650_start_count = 0;
 758     private int rt_29650_commit_count = 0;
 759     private int rt_29650_cancel_count = 0;
 760     @Test public void test_rt_29650() {
 761         listView.setOnEditStart(t -> {
 762             rt_29650_start_count++;
 763         });
 764         listView.setOnEditCommit(t -> {
 765             rt_29650_commit_count++;
 766         });
 767         listView.setOnEditCancel(t -> {
 768             rt_29650_cancel_count++;
 769         });
 770 
 771         listView.getItems().setAll("one", "two", "three", "four", "five");
 772         listView.setEditable(true);
 773         listView.setCellFactory(TextFieldListCell.forListView());
 774 
 775         StageLoader sl = new StageLoader(listView);
 776 
 777         listView.edit(0);
 778 
 779         Toolkit.getToolkit().firePulse();
 780 
 781         ListCell rootCell = (ListCell) VirtualFlowTestUtils.getCell(listView, 0);
 782         TextField textField = (TextField) rootCell.getGraphic();
 783         textField.setText("Testing!");
 784         KeyEventFirer keyboard = new KeyEventFirer(textField);
 785         keyboard.doKeyPress(KeyCode.ENTER);
 786 
 787         // TODO should the following assert be enabled?
 788 //        assertEquals("Testing!", listView.getItems().get(0));
 789         assertEquals(1, rt_29650_start_count);
 790         assertEquals(1, rt_29650_commit_count);
 791         assertEquals(0, rt_29650_cancel_count);
 792 
 793         sl.dispose();
 794     }
 795 
 796     @Test public void test_rt35039() {
 797         final List<String> data = new ArrayList<>();
 798         data.add("aabbaa");
 799         data.add("bbc");
 800 
 801         final ListView<String> listView = new ListView<>();
 802         listView.setItems(FXCollections.observableArrayList(data));
 803 
 804         StageLoader sl = new StageLoader(listView);
 805 
 806         // selection starts off on row -1
 807         assertNull(listView.getSelectionModel().getSelectedItem());
 808 
 809         // select "bbc" and ensure everything is set to that
 810         listView.getSelectionModel().select(1);
 811         assertEquals("bbc", listView.getSelectionModel().getSelectedItem());
 812 
 813         // change the items list - but retain the same content. We expect
 814         // that "bbc" remains selected as it is still in the list
 815         listView.setItems(FXCollections.observableArrayList(data));
 816         assertEquals("bbc", listView.getSelectionModel().getSelectedItem());
 817 
 818         sl.dispose();
 819     }
 820 
 821     @Test public void test_rt35857() {
 822         ObservableList<String> fxList = FXCollections.observableArrayList("A", "B", "C");
 823         final ListView<String> listView = new ListView<String>(fxList);
 824 
 825         listView.getSelectionModel().select(0);
 826 
 827         ObservableList<String> selectedItems = listView.getSelectionModel().getSelectedItems();
 828         assertEquals(1, selectedItems.size());
 829         assertEquals("A", selectedItems.get(0));
 830 
 831         listView.getItems().removeAll(selectedItems);
 832         assertEquals(2, fxList.size());
 833         assertEquals("B", fxList.get(0));
 834         assertEquals("C", fxList.get(1));
 835     }
 836 
 837     private int rt_35889_cancel_count = 0;
 838     @Test public void test_rt35889() {
 839         final ListView<String> textFieldListView = new ListView<String>();
 840         textFieldListView.setItems(FXCollections.observableArrayList("A", "B", "C"));
 841         textFieldListView.setEditable(true);
 842         textFieldListView.setCellFactory(TextFieldListCell.forListView());
 843         textFieldListView.setOnEditCancel(t -> {
 844             rt_35889_cancel_count++;
 845             System.out.println("On Edit Cancel: " + t);
 846         });
 847 
 848         ListCell cell0 = (ListCell) VirtualFlowTestUtils.getCell(textFieldListView, 0);
 849         assertNull(cell0.getGraphic());
 850         assertEquals("A", cell0.getText());
 851 
 852         textFieldListView.edit(0);
 853         TextField textField = (TextField) cell0.getGraphic();
 854         assertNotNull(textField);
 855 
 856         assertEquals(0, rt_35889_cancel_count);
 857 
 858         textField.setText("Z");
 859         KeyEventFirer keyboard = new KeyEventFirer(textField);
 860         keyboard.doKeyPress(KeyCode.ENTER);
 861 
 862         assertEquals(0, rt_35889_cancel_count);
 863     }
 864 
 865     @Test public void test_rt25679() {
 866         Button focusBtn = new Button("Focus here");
 867 
 868         final ListView<String> listView = new ListView<String>();
 869         SelectionModel sm = listView.getSelectionModel();
 870         listView.setItems(FXCollections.observableArrayList("A", "B", "C"));
 871 
 872         VBox vbox = new VBox(focusBtn, listView);
 873 
 874         StageLoader sl = new StageLoader(vbox);
 875         sl.getStage().requestFocus();
 876         focusBtn.requestFocus();
 877         Toolkit.getToolkit().firePulse();
 878 
 879         // test initial state
 880         assertEquals(sl.getStage().getScene().getFocusOwner(), focusBtn);
 881         assertTrue(focusBtn.isFocused());
 882         assertEquals(-1, sm.getSelectedIndex());
 883         assertNull(sm.getSelectedItem());
 884 
 885         // move focus to the listview
 886         listView.requestFocus();
 887 
 888         // ensure that there is a selection (where previously there was not one)
 889         assertEquals(sl.getStage().getScene().getFocusOwner(), listView);
 890         assertTrue(listView.isFocused());
 891         assertEquals(-1, sm.getSelectedIndex());
 892         assertNull(sm.getSelectedItem());
 893 
 894         sl.dispose();
 895     }
 896 
 897     private int rt_37061_index_counter = 0;
 898     private int rt_37061_item_counter = 0;
 899     @Test public void test_rt_37061() {
 900         ListView<Integer> tv = new ListView<>();
 901         tv.getItems().add(1);
 902         tv.getSelectionModel().select(0);
 903 
 904         // note we add the listeners after the selection is made, so the counters
 905         // at this point are still both at zero.
 906         tv.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
 907             rt_37061_index_counter++;
 908         });
 909 
 910         tv.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
 911             rt_37061_item_counter++;
 912         });
 913 
 914         // add a new item. This does not impact the selected index or selected item
 915         // so the counters should remain at zero.
 916         tv.getItems().add(2);
 917         assertEquals(0, rt_37061_index_counter);
 918         assertEquals(0, rt_37061_item_counter);
 919     }
 920 
 921     private int rt_37538_count = 0;
 922     @Test public void test_rt_37538_noCNextCall() {
 923         test_rt_37538(false, false);
 924     }
 925 
 926     @Test public void test_rt_37538_callCNextOnce() {
 927         test_rt_37538(true, false);
 928     }
 929 
 930     @Test public void test_rt_37538_callCNextInLoop() {
 931         test_rt_37538(false, true);
 932     }
 933 
 934     private void test_rt_37538(boolean callCNextOnce, boolean callCNextInLoop) {
 935         ListView<Integer> list = new ListView<>();
 936         for ( int i = 1; i <= 50; i++ ) {
 937             list.getItems().add(i);
 938         }
 939 
 940         list.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends Integer> c) -> {
 941             if (callCNextOnce) {
 942                 c.next();
 943             } else if (callCNextInLoop) {
 944                 while (c.next()) {
 945                     // no-op
 946                 }
 947             }
 948 
 949             if (rt_37538_count >= 1) {
 950                 Thread.dumpStack();
 951                 fail("This method should only be called once");
 952             }
 953 
 954             rt_37538_count++;
 955         });
 956 
 957         StageLoader sl = new StageLoader(list);
 958         assertEquals(0, rt_37538_count);
 959         list.getSelectionModel().select(0);
 960         assertEquals(1, rt_37538_count);
 961         sl.dispose();
 962     }
 963 
 964     @Test
 965     public void test_rt_35395_fixedCellSize() {
 966         test_rt_35395(true);
 967     }
 968 
 969     @Test
 970     public void test_rt_35395_notFixedCellSize() {
 971         test_rt_35395(false);
 972     }
 973 
 974     private int rt_35395_counter;
 975 
 976     private void test_rt_35395(boolean useFixedCellSize) {
 977         rt_35395_counter = 0;
 978 
 979         ObservableList<String> items = FXCollections.observableArrayList();
 980         for (int i = 0; i < 20; ++i) {
 981             items.addAll("red", "green", "blue", "purple");
 982         }
 983 
 984         ListView<String> listView = new ListView<>(items);
 985         if (useFixedCellSize) {
 986             listView.setFixedCellSize(24);
 987         }
 988         listView.setCellFactory(lv -> new ListCell<String>() {
 989             @Override
 990             protected void updateItem(String color, boolean empty) {
 991                 rt_35395_counter += 1;
 992                 super.updateItem(color, empty);
 993                 setText(null);
 994                 if (empty) {
 995                     setGraphic(null);
 996                 } else {
 997                     Rectangle rect = new Rectangle(16, 16);
 998                     rect.setStyle("-fx-fill: " + color);
 999                     setGraphic(rect);
1000                 }
1001             }
1002         });
1003 
1004         StageLoader sl = new StageLoader(listView);
1005 
1006         Platform.runLater(() -> {
1007             rt_35395_counter = 0;
1008             items.set(10, "yellow");
1009             Platform.runLater(() -> {
1010                 Toolkit.getToolkit().firePulse();
1011                 assertEquals(1, rt_35395_counter);
1012                 rt_35395_counter = 0;
1013                 items.set(30, "yellow");
1014                 Platform.runLater(() -> {
1015                     Toolkit.getToolkit().firePulse();
1016                     assertEquals(0, rt_35395_counter);
1017                     rt_35395_counter = 0;
1018                     items.remove(12);
1019                     Platform.runLater(() -> {
1020                         Toolkit.getToolkit().firePulse();
1021                         assertEquals(useFixedCellSize ? 39 : 45, rt_35395_counter);
1022                         rt_35395_counter = 0;
1023                         items.add(12, "yellow");
1024                         Platform.runLater(() -> {
1025                             Toolkit.getToolkit().firePulse();
1026                             assertEquals(useFixedCellSize ? 39 : 45, rt_35395_counter);
1027                             rt_35395_counter = 0;
1028                             listView.scrollTo(5);
1029                             Platform.runLater(() -> {
1030                                 Toolkit.getToolkit().firePulse();
1031                                 assertEquals(5, rt_35395_counter);
1032                                 rt_35395_counter = 0;
1033                                 listView.scrollTo(55);
1034                                 Platform.runLater(() -> {
1035                                     Toolkit.getToolkit().firePulse();
1036                                     assertEquals(useFixedCellSize ? 17 : 53, rt_35395_counter);
1037                                     sl.dispose();
1038                                 });
1039                             });
1040                         });
1041                     });
1042                 });
1043             });
1044         });
1045     }
1046 
1047     @Test public void test_rt_37632() {
1048         final ObservableList<String> listOne = FXCollections.observableArrayList("A", "B", "C");
1049         final ObservableList<String> listTwo = FXCollections.observableArrayList("C");
1050 
1051         final ListView<String> listView = new ListView<>();
1052         MultipleSelectionModel<String> sm = listView.getSelectionModel();
1053         listView.setItems(listOne);
1054         listView.getSelectionModel().selectFirst();
1055 
1056         assertEquals(0, sm.getSelectedIndex());
1057         assertEquals("A", sm.getSelectedItem());
1058         assertEquals(1, sm.getSelectedIndices().size());
1059         assertEquals(0, (int) sm.getSelectedIndices().get(0));
1060         assertEquals(1, sm.getSelectedItems().size());
1061         assertEquals("A", sm.getSelectedItems().get(0));
1062 
1063         listView.setItems(listTwo);
1064 
1065         assertEquals(-1, sm.getSelectedIndex());
1066         assertNull(sm.getSelectedItem());
1067         assertEquals(0, sm.getSelectedIndices().size());
1068         assertEquals(0, sm.getSelectedItems().size());
1069     }
1070 
1071     private int rt_37853_cancelCount;
1072     private int rt_37853_commitCount;
1073     @Test public void test_rt_37853() {
1074         listView.setCellFactory(TextFieldListCell.forListView());
1075         listView.setEditable(true);
1076 
1077         for (int i = 0; i < 10; i++) {
1078             listView.getItems().add("" + i);
1079         }
1080 
1081         StageLoader sl = new StageLoader(listView);
1082 
1083         listView.setOnEditCancel(editEvent -> rt_37853_cancelCount++);
1084         listView.setOnEditCommit(editEvent -> rt_37853_commitCount++);
1085 
1086         assertEquals(0, rt_37853_cancelCount);
1087         assertEquals(0, rt_37853_commitCount);
1088 
1089         listView.edit(1);
1090         assertNotNull(listView.getEditingIndex());
1091 
1092         listView.getItems().clear();
1093         assertEquals(1, rt_37853_cancelCount);
1094         assertEquals(0, rt_37853_commitCount);
1095 
1096         sl.dispose();
1097     }
1098 
1099     @Test public void test_rt_38787_remove_b() {
1100         // selection moves to "a"
1101         test_rt_38787("a", 0, "b");
1102     }
1103 
1104     @Test public void test_rt_38787_remove_b_c() {
1105         // selection moves to "a"
1106         test_rt_38787("a", 0, "b", "c");
1107     }
1108 
1109     @Test public void test_rt_38787_remove_c_d() {
1110         // selection moves to "b"
1111         test_rt_38787("b", 1, "c", "d");
1112     }
1113 
1114     @Test public void test_rt_38787_remove_a() {
1115         // selection moves to "b", now in index 0
1116         test_rt_38787("b", 0, "a");
1117     }
1118 
1119     @Test public void test_rt_38787_remove_z() {
1120         // selection shouldn't move as 'z' doesn't exist
1121         test_rt_38787("b", 1, "z");
1122     }
1123 
1124     private void test_rt_38787(String expectedItem, int expectedIndex, String... itemsToRemove) {
1125         ListView<String> stringListView = new ListView<>();
1126         stringListView.getItems().addAll("a","b","c","d");
1127 
1128         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1129         sm.select("b");
1130 
1131         // test pre-conditions
1132         assertEquals(1, sm.getSelectedIndex());
1133         assertEquals(1, (int)sm.getSelectedIndices().get(0));
1134         assertEquals("b", sm.getSelectedItem());
1135         assertEquals("b", sm.getSelectedItems().get(0));
1136         assertFalse(sm.isSelected(0));
1137         assertTrue(sm.isSelected(1));
1138         assertFalse(sm.isSelected(2));
1139 
1140         // removing items
1141         stringListView.getItems().removeAll(itemsToRemove);
1142 
1143         // testing against expectations
1144         assertEquals(expectedIndex, sm.getSelectedIndex());
1145         assertEquals(expectedIndex, (int)sm.getSelectedIndices().get(0));
1146         assertEquals(expectedItem, sm.getSelectedItem());
1147         assertEquals(expectedItem, sm.getSelectedItems().get(0));
1148     }
1149 
1150     private int rt_38341_indices_count = 0;
1151     private int rt_38341_items_count = 0;
1152     @Test public void test_rt_38341() {
1153         ListView<String> stringListView = new ListView<>();
1154         stringListView.getItems().addAll("a","b","c","d");
1155 
1156         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1157         sm.getSelectedIndices().addListener((ListChangeListener<Integer>) c -> rt_38341_indices_count++);
1158         sm.getSelectedItems().addListener((ListChangeListener<String>) c -> rt_38341_items_count++);
1159 
1160         assertEquals(0, rt_38341_indices_count);
1161         assertEquals(0, rt_38341_items_count);
1162 
1163         // expand the first child of root, and select it (note: root isn't visible)
1164         sm.select(1);
1165         assertEquals(1, sm.getSelectedIndex());
1166         assertEquals(1, sm.getSelectedIndices().size());
1167         assertEquals(1, (int)sm.getSelectedIndices().get(0));
1168         assertEquals(1, sm.getSelectedItems().size());
1169         assertEquals("b", sm.getSelectedItem());
1170         assertEquals("b", sm.getSelectedItems().get(0));
1171 
1172         assertEquals(1, rt_38341_indices_count);
1173         assertEquals(1, rt_38341_items_count);
1174 
1175         // now delete it
1176         stringListView.getItems().remove(1);
1177 
1178         // selection should move to the childs parent in index 0
1179         assertEquals(0, sm.getSelectedIndex());
1180         assertEquals(1, sm.getSelectedIndices().size());
1181         assertEquals(0, (int)sm.getSelectedIndices().get(0));
1182         assertEquals(1, sm.getSelectedItems().size());
1183         assertEquals("a", sm.getSelectedItem());
1184         assertEquals("a", sm.getSelectedItems().get(0));
1185 
1186         // we also expect there to be an event in the selection model for
1187         // selected indices and selected items
1188         assertEquals(sm.getSelectedIndices() +"", 2, rt_38341_indices_count);
1189         assertEquals(2, rt_38341_items_count);
1190     }
1191 
1192     @Test public void test_rt_39132() {
1193         ObservableList items = FXCollections.observableArrayList("one", "two", "three");
1194         ListView listView = new ListView<>();
1195         listView.setItems(items);
1196 
1197         MultipleSelectionModel sm = listView.getSelectionModel();
1198         sm.select(0);
1199 
1200         assertEquals(0, sm.getSelectedIndex());
1201         assertEquals("one", sm.getSelectedItem());
1202 
1203         items.add(0, "new item");
1204         assertEquals(1, sm.getSelectedIndex());
1205         assertEquals("one", sm.getSelectedItem());
1206     }
1207 
1208     private int rt_38943_index_count = 0;
1209     private int rt_38943_item_count = 0;
1210     @Test public void test_rt_38943() {
1211         ListView<String> listView = new ListView<>(FXCollections.observableArrayList("one", "two", "three"));
1212 
1213         MultipleSelectionModel sm = listView.getSelectionModel();
1214 
1215         sm.selectedIndexProperty().addListener((observable, oldValue, newValue) -> rt_38943_index_count++);
1216         sm.selectedItemProperty().addListener((observable, oldValue, newValue) -> rt_38943_item_count++);
1217 
1218         assertEquals(-1, sm.getSelectedIndex());
1219         assertNull(sm.getSelectedItem());
1220         assertEquals(0, rt_38943_index_count);
1221         assertEquals(0, rt_38943_item_count);
1222 
1223         sm.select(0);
1224         assertEquals(0, sm.getSelectedIndex());
1225         assertEquals("one", sm.getSelectedItem());
1226         assertEquals(1, rt_38943_index_count);
1227         assertEquals(1, rt_38943_item_count);
1228 
1229         sm.clearSelection(0);
1230         assertEquals(-1, sm.getSelectedIndex());
1231         assertNull(sm.getSelectedItem());
1232         assertEquals(2, rt_38943_index_count);
1233         assertEquals(2, rt_38943_item_count);
1234     }
1235 
1236     @Test public void test_rt_38884() {
1237         ListView<String> listView = new ListView<>();
1238         ObservableList<String> items = listView.getItems();
1239 
1240         listView.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends String> c) -> {
1241             while (c.next()) {
1242                 if (c.wasRemoved()) {
1243                     assertTrue(c.getRemovedSize() > 0);
1244 
1245                     List<? extends String> removed = c.getRemoved();
1246                     String removedItem = null;
1247                     try {
1248                         removedItem = removed.get(0);
1249                     } catch (Exception e) {
1250                         fail();
1251                     }
1252 
1253                     assertEquals("foo", removedItem);
1254                 }
1255             }
1256         });
1257 
1258         items.add("foo");
1259         listView.getSelectionModel().select(0);
1260         items.clear();
1261     }
1262 
1263     private int rt_37360_add_count = 0;
1264     private int rt_37360_remove_count = 0;
1265     @Test public void test_rt_37360() {
1266         ListView<String> stringListView = new ListView<>();
1267         stringListView.getItems().addAll("a", "b");
1268 
1269         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1270         sm.setSelectionMode(SelectionMode.MULTIPLE);
1271         sm.getSelectedItems().addListener((ListChangeListener<String>) c -> {
1272             while (c.next()) {
1273                 if (c.wasAdded()) {
1274                     rt_37360_add_count += c.getAddedSize();
1275                 }
1276                 if (c.wasRemoved()) {
1277                     rt_37360_remove_count += c.getRemovedSize();
1278                 }
1279             }
1280         });
1281 
1282         assertEquals(0, sm.getSelectedItems().size());
1283         assertEquals(0, rt_37360_add_count);
1284         assertEquals(0, rt_37360_remove_count);
1285 
1286         sm.select(0);
1287         assertEquals(1, sm.getSelectedItems().size());
1288         assertEquals(1, rt_37360_add_count);
1289         assertEquals(0, rt_37360_remove_count);
1290 
1291         sm.select(1);
1292         assertEquals(2, sm.getSelectedItems().size());
1293         assertEquals(2, rt_37360_add_count);
1294         assertEquals(0, rt_37360_remove_count);
1295 
1296         sm.clearAndSelect(1);
1297         assertEquals(1, sm.getSelectedItems().size());
1298         assertEquals(2, rt_37360_add_count);
1299         assertEquals(1, rt_37360_remove_count);
1300     }
1301 
1302     @Test public void test_rt_38491() {
1303         ListView<String> stringListView = new ListView<>();
1304         stringListView.getItems().addAll("a", "b");
1305 
1306         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1307         sm.setSelectionMode(SelectionMode.MULTIPLE);
1308 
1309         FocusModel<String> fm = stringListView.getFocusModel();
1310 
1311         // click on row 0
1312         VirtualFlowTestUtils.clickOnRow(stringListView, 0);
1313         assertTrue(sm.isSelected(0));
1314         assertEquals("a", sm.getSelectedItem());
1315         assertTrue(fm.isFocused(0));
1316         assertEquals("a", fm.getFocusedItem());
1317         assertEquals(0, fm.getFocusedIndex());
1318 
1319         int anchor = ListCellBehavior.getAnchor(stringListView, null);
1320         assertTrue(ListCellBehavior.hasNonDefaultAnchor(stringListView));
1321         assertEquals(0, anchor);
1322 
1323         // now add a new item at row 0. This has the effect of pushing down
1324         // the selected item into row 1.
1325         stringListView.getItems().add(0, "z");
1326 
1327         // The first bug was that selection and focus were not moving down to
1328         // be on row 1, so we test that now
1329         assertFalse(sm.isSelected(0));
1330         assertFalse(fm.isFocused(0));
1331         assertTrue(sm.isSelected(1));
1332         assertEquals("a", sm.getSelectedItem());
1333         assertTrue(fm.isFocused(1));
1334         assertEquals("a", fm.getFocusedItem());
1335         assertEquals(1, fm.getFocusedIndex());
1336 
1337         // The second bug was that the anchor was not being pushed down as well
1338         // (when it should).
1339         anchor = ListCellBehavior.getAnchor(stringListView, null);
1340         assertTrue(ListCellBehavior.hasNonDefaultAnchor(stringListView));
1341         assertEquals(1, anchor);
1342     }
1343 
1344     private final ObservableList<String> rt_39256_list = FXCollections.observableArrayList();
1345     @Test public void test_rt_39256() {
1346         ListView<String> stringListView = new ListView<>();
1347         stringListView.getItems().addAll("a","b", "c", "d");
1348 
1349         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1350         sm.setSelectionMode(SelectionMode.MULTIPLE);
1351 
1352 //        rt_39256_list.addListener((ListChangeListener<String>) change -> {
1353 //            while (change.next()) {
1354 //                System.err.println("number of selected persons (in bound list): " + change.getList().size());
1355 //            }
1356 //        });
1357 
1358         Bindings.bindContent(rt_39256_list, sm.getSelectedItems());
1359 
1360         assertEquals(0, sm.getSelectedItems().size());
1361         assertEquals(0, rt_39256_list.size());
1362 
1363         sm.selectAll();
1364         assertEquals(4, sm.getSelectedItems().size());
1365         assertEquals(4, rt_39256_list.size());
1366 
1367         sm.selectAll();
1368         assertEquals(4, sm.getSelectedItems().size());
1369         assertEquals(4, rt_39256_list.size());
1370 
1371         sm.selectAll();
1372         assertEquals(4, sm.getSelectedItems().size());
1373         assertEquals(4, rt_39256_list.size());
1374     }
1375 
1376     private final ObservableList<String> rt_39482_list = FXCollections.observableArrayList();
1377     @Test public void test_rt_39482() {
1378         ListView<String> stringListView = new ListView<>();
1379         stringListView.getItems().addAll("a", "b", "c", "d");
1380 
1381         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1382         sm.setSelectionMode(SelectionMode.MULTIPLE);
1383 
1384         sm.getSelectedItems().addListener((ListChangeListener<String>) change -> {
1385             while (change.next()) {
1386                 System.out.println("sm.getSelectedItems(): " + change.getList());
1387             }
1388         });
1389 
1390         rt_39482_list.addListener((ListChangeListener<String>) change -> {
1391             while (change.next()) {
1392                 System.out.println("rt_39482_list: " + change.getList());
1393             }
1394         });
1395 
1396         Bindings.bindContent(rt_39482_list, sm.getSelectedItems());
1397 
1398         assertEquals(0, sm.getSelectedItems().size());
1399         assertEquals(0, rt_39482_list.size());
1400 
1401         test_rt_39482_selectRow("a", sm, 0);
1402         test_rt_39482_selectRow("b", sm, 1);
1403         test_rt_39482_selectRow("c", sm, 2);
1404         test_rt_39482_selectRow("d", sm, 3);
1405     }
1406 
1407     private void test_rt_39482_selectRow(String expectedString,
1408                                          MultipleSelectionModel<String> sm,
1409                                          int rowToSelect) {
1410         System.out.println("\nSelect row " + rowToSelect);
1411         sm.selectAll();
1412         assertEquals(4, sm.getSelectedIndices().size());
1413         assertEquals(4, sm.getSelectedItems().size());
1414         assertEquals(4, rt_39482_list.size());
1415 
1416         sm.clearAndSelect(rowToSelect);
1417         assertEquals(1, sm.getSelectedIndices().size());
1418         assertEquals(1, sm.getSelectedItems().size());
1419         assertEquals(expectedString, sm.getSelectedItem());
1420         assertEquals(expectedString, rt_39482_list.get(0));
1421         assertEquals(1, rt_39482_list.size());
1422     }
1423 
1424     @Test public void test_rt_39559_useSM_selectAll() {
1425         test_rt_39559(true);
1426     }
1427 
1428     @Test public void test_rt_39559_useKeyboard_selectAll() {
1429         test_rt_39559(false);
1430     }
1431 
1432     private void test_rt_39559(boolean useSMSelectAll) {
1433         ListView<String> stringListView = new ListView<>();
1434         stringListView.getItems().addAll("a", "b", "c", "d");
1435 
1436         MultipleSelectionModel<String> sm = stringListView.getSelectionModel();
1437         sm.setSelectionMode(SelectionMode.MULTIPLE);
1438 
1439         StageLoader sl = new StageLoader(stringListView);
1440         KeyEventFirer keyboard = new KeyEventFirer(stringListView);
1441 
1442         assertEquals(0, sm.getSelectedItems().size());
1443 
1444         sm.clearAndSelect(0);
1445 
1446         if (useSMSelectAll) {
1447             sm.selectAll();
1448         } else {
1449             keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
1450         }
1451 
1452         assertEquals(4, sm.getSelectedItems().size());
1453         assertEquals(0, (int) ListCellBehavior.getAnchor(stringListView, -1));
1454 
1455         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);
1456 
1457         assertEquals(0, (int) ListCellBehavior.getAnchor(stringListView, -1));
1458         assertEquals(2, sm.getSelectedItems().size());
1459         assertEquals("a", sm.getSelectedItems().get(0));
1460         assertEquals("b", sm.getSelectedItems().get(1));
1461 
1462         sl.dispose();
1463     }
1464 
1465     @Test public void test_rt_16068_firstElement_selectAndRemoveSameRow() {
1466         // select and then remove the 'a' item, selection and focus should both
1467         // stay at the first row, now 'b'
1468         test_rt_16068(0, 0, 0);
1469     }
1470 
1471     @Test public void test_rt_16068_firstElement_selectRowAndRemoveLaterSibling() {
1472         // select row 'a', and remove row 'c', selection and focus should not change
1473         test_rt_16068(0, 2, 0);
1474     }
1475 
1476     @Test public void test_rt_16068_middleElement_selectAndRemoveSameRow() {
1477         // select and then remove the 'b' item, selection and focus should both
1478         // move up one row to the 'a' item
1479         test_rt_16068(1, 1, 0);
1480     }
1481 
1482     @Test public void test_rt_16068_middleElement_selectRowAndRemoveLaterSibling() {
1483         // select row 'b', and remove row 'c', selection and focus should not change
1484         test_rt_16068(1, 2, 1);
1485     }
1486 
1487     @Test public void test_rt_16068_middleElement_selectRowAndRemoveEarlierSibling() {
1488         // select row 'b', and remove row 'a', selection and focus should move up
1489         // one row, remaining on 'b'
1490         test_rt_16068(1, 0, 0);
1491     }
1492 
1493     @Test public void test_rt_16068_lastElement_selectAndRemoveSameRow() {
1494         // select and then remove the 'd' item, selection and focus should both
1495         // move up one row to the 'c' item
1496         test_rt_16068(3, 3, 2);
1497     }
1498 
1499     @Test public void test_rt_16068_lastElement_selectRowAndRemoveEarlierSibling() {
1500         // select row 'd', and remove row 'a', selection and focus should move up
1501         // one row, remaining on 'd'
1502         test_rt_16068(3, 0, 2);
1503     }
1504 
1505     private void test_rt_16068(int indexToSelect, int indexToRemove, int expectedIndex) {
1506         ListView<String> stringListView = new ListView<>();
1507         stringListView.getItems().addAll("a", "b", "c", "d");
1508 
1509         MultipleSelectionModel<?> sm = stringListView.getSelectionModel();
1510         FocusModel<?> fm = stringListView.getFocusModel();
1511 
1512         sm.select(indexToSelect);
1513         assertEquals(indexToSelect, sm.getSelectedIndex());
1514         assertEquals(stringListView.getItems().get(indexToSelect), sm.getSelectedItem());
1515         assertEquals(indexToSelect, fm.getFocusedIndex());
1516         assertEquals(stringListView.getItems().get(indexToSelect), fm.getFocusedItem());
1517 
1518         stringListView.getItems().remove(indexToRemove);
1519         assertEquals(expectedIndex, sm.getSelectedIndex());
1520         assertEquals(stringListView.getItems().get(expectedIndex), sm.getSelectedItem());
1521         assertEquals(expectedIndex, fm.getFocusedIndex());
1522         assertEquals(stringListView.getItems().get(expectedIndex), fm.getFocusedItem());
1523     }
1524 
1525     @Test public void test_rt_22599() {
1526         ObservableList<RT22599_DataType> initialData = FXCollections.observableArrayList(
1527                 new RT22599_DataType(1, "row1"),
1528                 new RT22599_DataType(2, "row2"),
1529                 new RT22599_DataType(3, "row3")
1530         );
1531 
1532         ListView<RT22599_DataType> listView = new ListView<>();
1533         listView.setItems(initialData);
1534 
1535         StageLoader sl = new StageLoader(listView);
1536 
1537         // testing initial state
1538         assertNotNull(listView.getSkin());
1539         assertEquals("row1", VirtualFlowTestUtils.getCell(listView, 0).getText());
1540         assertEquals("row2", VirtualFlowTestUtils.getCell(listView, 1).getText());
1541         assertEquals("row3", VirtualFlowTestUtils.getCell(listView, 2).getText());
1542 
1543         // change row 0 (where "row1" currently resides), keeping same id.
1544         // Because 'set' is called, the control should update to the new content
1545         // without any user interaction
1546         RT22599_DataType data;
1547         initialData.set(0, data = new RT22599_DataType(0, "row1a"));
1548         Toolkit.getToolkit().firePulse();
1549         assertEquals("row1a", VirtualFlowTestUtils.getCell(listView, 0).getText());
1550 
1551         // change the row 0 (where we currently have "row1a") value directly.
1552         // Because there is no associated property, this won't be observed, so
1553         // the control should still show "row1a" rather than "row1b"
1554         data.text = "row1b";
1555         Toolkit.getToolkit().firePulse();
1556         assertEquals("row1a", VirtualFlowTestUtils.getCell(listView, 0).getText());
1557 
1558         // call refresh() to force a refresh of all visible cells
1559         listView.refresh();
1560         Toolkit.getToolkit().firePulse();
1561         assertEquals("row1b", VirtualFlowTestUtils.getCell(listView, 0).getText());
1562 
1563         sl.dispose();
1564     }
1565 
1566     private static class RT22599_DataType {
1567         public int id = 0;
1568         public String text = "";
1569 
1570         public RT22599_DataType(int id, String text) {
1571             this.id = id;
1572             this.text = text;
1573         }
1574 
1575         @Override public String toString() {
1576             return text;
1577         }
1578 
1579         @Override public boolean equals(Object obj) {
1580             if (obj == null) return false;
1581             return id == ((RT22599_DataType)obj).id;
1582         }
1583     }
1584 
1585     private int rt_39966_count = 0;
1586     @Test public void test_rt_39966() {
1587         ObservableList<String> list = FXCollections.observableArrayList("Hello World");
1588         ListView<String> listView = new ListView<>(list);
1589 
1590         StageLoader sl = new StageLoader(listView);
1591 
1592         // initially there is no selection
1593         assertTrue(listView.getSelectionModel().isEmpty());
1594 
1595         listView.getSelectionModel().selectedItemProperty().addListener((value, s1, s2) -> {
1596             if (rt_39966_count == 0) {
1597                 rt_39966_count++;
1598                 assertFalse(listView.getSelectionModel().isEmpty());
1599             } else {
1600                 assertTrue(listView.getSelectionModel().isEmpty());
1601             }
1602         });
1603 
1604         // our assertion two lines down always succeeds. What fails is our
1605         // assertion above within the listener.
1606         listView.getSelectionModel().select(0);
1607         assertFalse(listView.getSelectionModel().isEmpty());
1608 
1609         list.remove(0);
1610         assertTrue(listView.getSelectionModel().isEmpty());
1611 
1612         sl.dispose();
1613     }
1614 
1615     /**
1616      * Bullet 1: selected index must be updated
1617      * Corner case: last selected. Fails for core
1618      */
1619     @Test public void test_rt_40012_selectedAtLastOnDisjointRemoveItemsAbove() {
1620         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1621         ListView<String> listView = new ListView<>(items);
1622         SelectionModel sm = listView.getSelectionModel();
1623 
1624         int last = items.size() - 1;
1625 
1626         // selecting item "5"
1627         sm.select(last);
1628 
1629         // disjoint remove of 2 elements above the last selected
1630         // Removing "1" and "3"
1631         items.removeAll(items.get(1), items.get(3));
1632 
1633         // selection should move up two places such that it remains on item "5",
1634         // but in index (last - 2).
1635         int expected = last - 2;
1636         assertEquals("5", sm.getSelectedItem());
1637         assertEquals("selected index after disjoint removes above", expected, sm.getSelectedIndex());
1638     }
1639 
1640     /**
1641      * Variant of 1: if selectedIndex is not updated,
1642      * the old index is no longer valid
1643      * for accessing the items.
1644      */
1645     @Test public void test_rt_40012_accessSelectedAtLastOnDisjointRemoveItemsAbove() {
1646         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1647         ListView<String> listView = new ListView<>(items);
1648         SelectionModel sm = listView.getSelectionModel();
1649 
1650         int last = items.size() - 1;
1651 
1652         // selecting item "5"
1653         sm.select(last);
1654 
1655         // disjoint remove of 2 elements above the last selected
1656         items.removeAll(items.get(1), items.get(3));
1657         int selected = sm.getSelectedIndex();
1658         if (selected > -1) {
1659             items.get(selected);
1660         }
1661     }
1662 
1663     /**
1664      * Bullet 2: selectedIndex notification count
1665      *
1666      * Note that we don't use the corner case of having the last index selected
1667      * (which fails already on updating the index)
1668      */
1669     private int rt_40012_count = 0;
1670     @Test public void test_rt_40012_selectedIndexNotificationOnDisjointRemovesAbove() {
1671         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1672         ListView<String> listView = new ListView<>(items);
1673         SelectionModel sm = listView.getSelectionModel();
1674 
1675         int last = items.size() - 2;
1676         sm.select(last);
1677         assertEquals(last, sm.getSelectedIndex());
1678 
1679         rt_40012_count = 0;
1680         sm.selectedIndexProperty().addListener(o -> rt_40012_count++);
1681 
1682         // disjoint remove of 2 elements above the last selected
1683         items.removeAll(items.get(1), items.get(3));
1684         assertEquals("sanity: selectedIndex must be shifted by -2", last - 2, sm.getSelectedIndex());
1685         assertEquals("must fire single event on removes above", 1, rt_40012_count);
1686     }
1687 
1688     /**
1689      * Bullet 3: unchanged selectedItem must not fire change
1690      */
1691     @Test
1692     public void test_rt_40012_selectedItemNotificationOnDisjointRemovesAbove() {
1693         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1694         ListView<String> listView = new ListView<>(items);
1695         SelectionModel sm = listView.getSelectionModel();
1696 
1697         int last = items.size() - 2;
1698         Object lastItem = items.get(last);
1699         sm.select(last);
1700         assertEquals(lastItem, sm.getSelectedItem());
1701 
1702         rt_40012_count = 0;
1703         sm.selectedItemProperty().addListener(o -> rt_40012_count++);
1704 
1705         // disjoint remove of 2 elements above the last selected
1706         items.removeAll(items.get(1), items.get(3));
1707         assertEquals("sanity: selectedItem unchanged", lastItem, sm.getSelectedItem());
1708         assertEquals("must not fire on unchanged selected item", 0, rt_40012_count);
1709     }
1710 
1711     @Test public void test_rt_40185() {
1712         final ListView<String> lv = new ListView<>();
1713         final ArrayList<Integer> expected = new ArrayList<>();
1714         Collections.addAll(expected, 1, 2);
1715 
1716         lv.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
1717         lv.getSelectionModel().getSelectedIndices().addListener((ListChangeListener<Integer>) change -> {
1718             while (change.next()) {
1719                 if (change.wasRemoved()) {
1720                     assertEquals(expected, change.getRemoved());
1721                 }
1722             }
1723         });
1724 
1725         lv.getItems().addAll("-0-","-1-","-2-");
1726         lv.getSelectionModel().selectIndices(1, 2);
1727         lv.getSelectionModel().clearSelection();
1728     }
1729 
1730     /**
1731      * ClearAndSelect fires invalid change event if selectedIndex is unchanged.
1732      */
1733     private int rt_40212_count = 0;
1734     @Test public void test_rt_40212() {
1735         final ListView<Integer> lv = new ListView<>();
1736         for (int i = 0; i < 10; i++) {
1737             lv.getItems().add(i);
1738         }
1739 
1740         MultipleSelectionModel<Integer> sm = lv.getSelectionModel();
1741         sm.setSelectionMode(SelectionMode.MULTIPLE);
1742 
1743         sm.selectRange(3, 5);
1744         int selected = sm.getSelectedIndex();
1745 
1746         sm.getSelectedIndices().addListener((ListChangeListener<Integer>) change -> {
1747             assertEquals("sanity: selectedIndex unchanged", selected, sm.getSelectedIndex());
1748             while(change.next()) {
1749                 assertEquals("single event on clearAndSelect already selected", 1, ++rt_40212_count);
1750 
1751                 boolean type = change.wasAdded() || change.wasRemoved() || change.wasPermutated() || change.wasUpdated();
1752                 assertTrue("at least one of the change types must be true", type);
1753             }
1754         });
1755 
1756         sm.clearAndSelect(selected);
1757     }
1758 
1759     @Test public void test_rt_40280() {
1760         final ListView<String> view = new ListView<>();
1761         StageLoader sl = new StageLoader(view);
1762         view.getFocusModel().getFocusedIndex();
1763         sl.dispose();
1764     }
1765 
1766     /**
1767      * Test list change of selectedIndices on setIndices. Fails for core ..
1768      */
1769     @Test public void test_rt_40263() {
1770         final ListView<Integer> lv = new ListView<>();
1771         for (int i = 0; i < 10; i++) {
1772             lv.getItems().add(i);
1773         }
1774 
1775         MultipleSelectionModel<Integer> sm = lv.getSelectionModel();
1776         sm.setSelectionMode(SelectionMode.MULTIPLE);
1777 
1778         int[] indices = new int[]{2, 5, 7};
1779         ListChangeListener<Integer> l = c -> {
1780             // firstly, we expect only one change
1781             int subChanges = 0;
1782             while(c.next()) {
1783                 subChanges++;
1784             }
1785             assertEquals(1, subChanges);
1786 
1787             // secondly, we expect the added size to be three, as that is the
1788             // number of items selected
1789             c.reset();
1790             c.next();
1791             System.out.println("Added items: " + c.getAddedSubList());
1792             assertEquals(indices.length, c.getAddedSize());
1793             assertArrayEquals(indices, c.getAddedSubList().stream().mapToInt(i -> i).toArray());
1794         };
1795         sm.getSelectedIndices().addListener(l);
1796         sm.selectIndices(indices[0], indices);
1797     }
1798 }