8191436: ListSelectionModel.setSelectionMode() underspecified

Reviewed-by: serb, ssadetsky
diff --git a/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java b/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java
index a055b51..312eec8 100644
--- a/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java
+++ b/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java
@@ -95,14 +95,37 @@
      * @throws IllegalArgumentException {@inheritDoc}
      */
     public void setSelectionMode(int selectionMode) {
+        int oldMode = this.selectionMode;
         switch (selectionMode) {
-        case SINGLE_SELECTION:
-        case SINGLE_INTERVAL_SELECTION:
-        case MULTIPLE_INTERVAL_SELECTION:
-            this.selectionMode = selectionMode;
-            break;
-        default:
-            throw new IllegalArgumentException("invalid selectionMode");
+            case SINGLE_SELECTION:
+            case SINGLE_INTERVAL_SELECTION:
+            case MULTIPLE_INTERVAL_SELECTION:
+                this.selectionMode = selectionMode;
+                break;
+            default:
+                throw new IllegalArgumentException("invalid selectionMode");
+        }
+
+        /*
+        This code will only be executed when selection needs to be updated on
+        changing selection mode. It will happen only if selection mode is changed
+        from MULTIPLE_INTERVAL to SINGLE_INTERVAL or SINGLE or from
+        SINGLE_INTERVAL to SINGLE
+         */
+        if (oldMode > this.selectionMode) {
+            if (this.selectionMode == SINGLE_SELECTION) {
+                if (!isSelectionEmpty()) {
+                    setSelectionInterval(minIndex, minIndex);
+                }
+            } else if (this.selectionMode == SINGLE_INTERVAL_SELECTION) {
+                if(!isSelectionEmpty()) {
+                    int selectionEndindex = minIndex;
+                    while (value.get(selectionEndindex + 1)) {
+                        selectionEndindex++;
+                    }
+                    setSelectionInterval(minIndex, selectionEndindex);
+                }
+            }
         }
     }
 
diff --git a/test/jdk/javax/swing/JList/ListSelectionModelTest.java b/test/jdk/javax/swing/JList/ListSelectionModelTest.java
new file mode 100644
index 0000000..7160465
--- /dev/null
+++ b/test/jdk/javax/swing/JList/ListSelectionModelTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @key headful
+ * @bug 8191436
+ * @summary Tests JListSelectionModel setSelection functionality
+ */
+
+import javax.swing.JList;
+import javax.swing.DefaultListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager.LookAndFeelInfo;
+
+import static javax.swing.UIManager.getInstalledLookAndFeels;
+import static javax.swing.UIManager.setLookAndFeel;
+
+import java.util.Arrays;
+
+public class ListSelectionModelTest {
+
+    public static void main(String[] args) throws Exception {
+
+        final LookAndFeelInfo[] lookAndFeelInfoArray =
+                getInstalledLookAndFeels();
+
+        for (LookAndFeelInfo lookAndFeelInfo : lookAndFeelInfoArray) {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        CreateGUIAndTest(lookAndFeelInfo.getClassName());
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        throw new RuntimeException("Exception while running test");
+                    }
+                }
+            });
+        }
+    }
+
+    static void CreateGUIAndTest(String lookAndFeel) throws Exception{
+        setLookAndFeel(lookAndFeel);
+        DefaultListModel listModel = new DefaultListModel();
+        for (int j = 0; j < 10; j++) {
+            listModel.add(j, "Item: " + j);
+        }
+
+        JList list = new JList(listModel);
+
+        ListSelectionModel selectionModel = list.getSelectionModel();
+        selectionModel.setSelectionMode(
+                ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+        selectionModel.setSelectionInterval(0, 1);
+        checkSelection(list, new int[]{0, 1}, lookAndFeel);
+
+        selectionModel.setSelectionMode(
+                ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        selectionModel.setSelectionInterval(0, 2);
+        checkSelection(list, new int[]{0, 1, 2}, lookAndFeel);
+
+        selectionModel.addSelectionInterval(5, 7);
+        checkSelection(list, new int[]{0, 1, 2, 5, 6, 7}, lookAndFeel);
+
+        selectionModel
+                .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+        checkSelection(list, new int[]{0, 1, 2}, lookAndFeel);
+
+        selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        checkSelection(list, new int[]{0}, lookAndFeel);
+
+        selectionModel
+                .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+        selectionModel.addSelectionInterval(4, 5);
+        checkSelection(list, new int[]{4, 5}, lookAndFeel);
+
+        selectionModel.addSelectionInterval(0, 2);
+        checkSelection(list, new int[]{0, 1, 2}, lookAndFeel);
+
+        selectionModel.setSelectionMode(
+                ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        selectionModel.addSelectionInterval(6, 7);
+        checkSelection(list, new int[]{0, 1, 2, 6, 7}, lookAndFeel);
+
+        System.out.println("Test passed for " + lookAndFeel);
+    }
+
+    static void checkSelection(JList list, int[] selectionArray,
+                               String lookAndFeel) throws RuntimeException {
+        int[] listSelection = list.getSelectedIndices();
+        if (listSelection.length != selectionArray.length) {
+            System.out.println("Expected: " + Arrays.toString(selectionArray));
+            System.out.println("Actual: " + Arrays.toString(listSelection));
+            throw new RuntimeException("Wrong selection for " + lookAndFeel);
+        }
+
+        Arrays.sort(listSelection);
+        Arrays.sort(selectionArray);
+
+        if (!Arrays.equals(listSelection, selectionArray)) {
+            System.out.println("Expected: " + Arrays.toString(selectionArray));
+            System.out.println("Actual: " + Arrays.toString(listSelection));
+            throw new RuntimeException("Wrong selection for " + lookAndFeel);
+        }
+    }
+}