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