diff --git a/modules/controls/src/main/java/javafx/scene/control/MultipleSelectionModelBase.java b/modules/controls/src/main/java/javafx/scene/control/MultipleSelectionModelBase.java --- a/modules/controls/src/main/java/javafx/scene/control/MultipleSelectionModelBase.java +++ b/modules/controls/src/main/java/javafx/scene/control/MultipleSelectionModelBase.java @@ -278,8 +278,12 @@ // This ensure that the selection remains accurate when a shift occurs. final int selectedIndex = getSelectedIndex(); - if (selectedIndex >= position && selectedIndex > -1 && selectedIndex + shift > -1) { - final int newSelectionLead = selectedIndex + shift; + if (selectedIndex >= position && selectedIndex > -1) { + // Fix for RT-38787: we used to not enter this block if + // selectedIndex + shift resulted in a value less than zero, whereas + // now we just set the newSelectionLead to zero in that instance. + // There exists unit tests that cover this. + final int newSelectionLead = Math.max(0, selectedIndex + shift); setSelectedIndex(newSelectionLead); // added for RT-30356 diff --git a/modules/controls/src/test/java/javafx/scene/control/ListViewTest.java b/modules/controls/src/test/java/javafx/scene/control/ListViewTest.java --- a/modules/controls/src/test/java/javafx/scene/control/ListViewTest.java +++ b/modules/controls/src/test/java/javafx/scene/control/ListViewTest.java @@ -1084,4 +1084,44 @@ sl.dispose(); } + + @Test public void test_rt_38787_removeOneItem() { + test_rt_38787(true); + } + + @Test public void test_rt_38787_removeMultipleItems() { + test_rt_38787(false); + } + + private void test_rt_38787(boolean removeOneItem) { + ListView stringListView = new ListView<>(); + stringListView.getItems().addAll("a","b","c","d"); + + MultipleSelectionModel sm = stringListView.getSelectionModel(); + sm.select("b"); + + // test pre-conditions + assertEquals(1, sm.getSelectedIndex()); + assertEquals(1, (int)sm.getSelectedIndices().get(0)); + assertEquals("b", sm.getSelectedItem()); + assertEquals("b", sm.getSelectedItems().get(0)); + assertFalse(sm.isSelected(0)); + assertTrue(sm.isSelected(1)); + assertFalse(sm.isSelected(2)); + + // in both cases we remove the selected item, that is, 'b' + if (removeOneItem) { + stringListView.getItems().remove("b"); + } else { + stringListView.getItems().removeAll("b","c"); + } + + assertEquals(0, sm.getSelectedIndex()); + assertEquals(0, (int)sm.getSelectedIndices().get(0)); + assertEquals("a", sm.getSelectedItem()); + assertEquals("a", sm.getSelectedItems().get(0)); + assertTrue(sm.isSelected(0)); + assertFalse(sm.isSelected(1)); + assertFalse(sm.isSelected(2)); + } } \ No newline at end of file