--- old/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/ReadOnlyUnbackedObservableList.java 2017-02-17 17:24:11.180438000 +0530 +++ new/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/ReadOnlyUnbackedObservableList.java 2017-02-17 17:24:10.972333999 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.NoSuchElementException; import javafx.beans.InvalidationListener; import com.sun.javafx.collections.ListListenerHelper; @@ -288,6 +289,7 @@ throw new UnsupportedOperationException("Not supported."); } + // Iterator to traverse the list of selected indices in both directions. private static class SelectionListIterator implements ListIterator { private int pos; private final ReadOnlyUnbackedObservableList list; @@ -306,6 +308,9 @@ } @Override public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } return list.get(pos++); } @@ -314,11 +319,14 @@ } @Override public E previous() { - return list.get(pos--); + if (!hasPrevious()) { + throw new NoSuchElementException(); + } + return list.get(--pos); } @Override public int nextIndex() { - return pos + 1; + return pos; } @Override public int previousIndex() { --- old/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java 2017-02-17 17:24:11.800748000 +0530 +++ new/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java 2017-02-17 17:24:11.560628000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.ObjectProperty; @@ -1830,4 +1832,90 @@ model.clearAndSelect(0); model.clearAndSelect(2); } + + @Test public void test_jdk_8145887_selectedIndices_ListIterator() { + int selectIndices[] = { 4, 7, 9 }; + ListView lv = new ListView<>(); + for (int i = 0; i < 10; ++i) { + lv.getItems().add(i); + } + + MultipleSelectionModel msm = lv.getSelectionModel(); + msm.setSelectionMode(SelectionMode.MULTIPLE); + for (int i = 0 ; i < selectIndices.length; ++i) { + msm.select(selectIndices[i]); + } + + ListIterator iter = lv.getSelectionModel().getSelectedIndices().listIterator(); + + // Step 1. Initial values + assertEquals(0, iter.nextIndex()); + assertEquals(-1, iter.previousIndex()); + assertEquals(true, iter.hasNext()); + assertEquals(false, iter.hasPrevious()); + + // Step 2. Iterate forward. + assertEquals(4, iter.next()); + assertEquals(1, iter.nextIndex()); + assertEquals(0, iter.previousIndex()); + assertEquals(true, iter.hasNext()); + assertEquals(true, iter.hasPrevious()); + + // Step 3. Iterate forward. + // Values would be at similar state of Step 2. + assertEquals(7, iter.next()); + + // Step 4. Iterate forward to Last element. + assertEquals(9, iter.next()); + assertEquals(3, iter.nextIndex()); + assertEquals(2, iter.previousIndex()); + assertEquals(false, iter.hasNext()); + assertEquals(true, iter.hasPrevious()); + + // Step 5. Verify NoSuchElementException by next() + try { + iter.next(); + } catch (Exception e) { + assert(e instanceof NoSuchElementException); + } + + // Step 6. Iterate backward to Last element. + assertEquals(9, iter.previous()); + assertEquals(2, iter.nextIndex()); + assertEquals(1, iter.previousIndex()); + assertEquals(true, iter.hasNext()); + assertEquals(true, iter.hasPrevious()); + + // Step 7. Iterate forward to Last element. + assertEquals(9, iter.next()); + assertEquals(3, iter.nextIndex()); + assertEquals(2, iter.previousIndex()); + assertEquals(false, iter.hasNext()); + assertEquals(true, iter.hasPrevious()); + + // Step 8. Iterate forward to last element. + // Values would be at Same state of Step 2. + assertEquals(9, iter.previous()); + + // Step 9. Iterate backward. + assertEquals(7, iter.previous()); + assertEquals(1, iter.nextIndex()); + assertEquals(0, iter.previousIndex()); + assertEquals(true, iter.hasNext()); + assertEquals(true, iter.hasPrevious()); + + // Step 10. Iterate back to first element. + assertEquals(4, iter.previous()); + assertEquals(0, iter.nextIndex()); + assertEquals(-1, iter.previousIndex()); + assertEquals(true, iter.hasNext()); + assertEquals(false, iter.hasPrevious()); + + // Step 11. Verify NoSuchElementException by previous() + try { + iter.previous(); + } catch (Exception e) { + assert(e instanceof NoSuchElementException); + } + } }