diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/BehaviorBase.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/BehaviorBase.java index edb69751ef..fa71e388a1 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/BehaviorBase.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/BehaviorBase.java @@ -88,7 +88,7 @@ protected void addDefaultMapping(InputMap inputMap, Mapping... newMapping) for (Mapping mapping : newMapping) { // check if a mapping already exists, and if so, do not add this mapping - // TODO this is insufficient as we need to check entire InputMap hierarchy + // TODO: JDK-8250807: this is insufficient as we need to check entire InputMap hierarchy // for (Mapping existingMapping : existingMappings) { // if (existingMapping != null && existingMapping.equals(mapping)) { // return; @@ -116,6 +116,7 @@ protected void addDefaultMapping(InputMap inputMap, Mapping... newMapping) } protected void removeMapping(Object key) { + // TODO: JDK-8250807: Traverse the child maps of getInputMap() and remove the mapping from them. InputMap inputMap = getInputMap(); inputMap.lookupMapping(key).ifPresent(mapping -> { inputMap.getMappings().remove(mapping); diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ComboBoxListViewBehavior.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ComboBoxListViewBehavior.java index 856c7c92e9..4146342225 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ComboBoxListViewBehavior.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ComboBoxListViewBehavior.java @@ -26,55 +26,9 @@ package com.sun.javafx.scene.control.behavior; import javafx.scene.control.ComboBox; -import javafx.scene.control.ComboBoxBase; -import javafx.scene.control.SelectionModel; -import com.sun.javafx.scene.control.inputmap.InputMap; - -import static javafx.scene.input.KeyCode.DOWN; -import static javafx.scene.input.KeyCode.UP; public class ComboBoxListViewBehavior extends ComboBoxBaseBehavior { - - /*************************************************************************** - * * - * Constructors * - * * - **************************************************************************/ - - /** - * - */ public ComboBoxListViewBehavior(final ComboBox comboBox) { super(comboBox); - - // Add these bindings as a child input map, so they take precedence - InputMap> comboBoxListViewInputMap = new InputMap<>(comboBox); - comboBoxListViewInputMap.getMappings().addAll( - new InputMap.KeyMapping(UP, e -> selectPrevious()), - new InputMap.KeyMapping(DOWN, e -> selectNext()) - ); - addDefaultChildMap(getInputMap(), comboBoxListViewInputMap); - } - - /*************************************************************************** - * * - * Key event handling * - * * - **************************************************************************/ - - private ComboBox getComboBox() { - return (ComboBox) getNode(); - } - - private void selectPrevious() { - SelectionModel sm = getComboBox().getSelectionModel(); - if (sm == null) return; - sm.selectPrevious(); - } - - private void selectNext() { - SelectionModel sm = getComboBox().getSelectionModel(); - if (sm == null) return; - sm.selectNext(); } } diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ListViewBehavior.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ListViewBehavior.java index cfc5c1ab7d..79f52424d3 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ListViewBehavior.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/ListViewBehavior.java @@ -46,6 +46,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; +import java.util.function.Supplier; import static com.sun.javafx.scene.control.inputmap.InputMap.*; import static javafx.scene.input.KeyCode.*; @@ -78,12 +80,19 @@ public ListViewBehavior(ListView control) { listViewInputMap = createInputMap(); // add focus traversal mappings - addDefaultMapping(listViewInputMap, FocusTraversalInputMap.getFocusTraversalMappings()); + Supplier isListViewOfComboBox = + (Supplier) control.getProperties().get("editableComboBox"); + Predicate isInComboBox = e -> isListViewOfComboBox != null; + Predicate isInEditableComboBox = + e -> isListViewOfComboBox != null && isListViewOfComboBox.get(); + if (isListViewOfComboBox == null) { + addDefaultMapping(listViewInputMap, FocusTraversalInputMap.getFocusTraversalMappings()); + } addDefaultMapping(listViewInputMap, - new KeyMapping(HOME, e -> selectFirstRow()), - new KeyMapping(END, e -> selectLastRow()), - new KeyMapping(new KeyBinding(HOME).shift(), e -> selectAllToFirstRow()), - new KeyMapping(new KeyBinding(END).shift(), e -> selectAllToLastRow()), + new KeyMapping(new KeyBinding(HOME), e -> selectFirstRow(), isInEditableComboBox), + new KeyMapping(new KeyBinding(END), e -> selectLastRow(), isInEditableComboBox), + new KeyMapping(new KeyBinding(HOME).shift(), e -> selectAllToFirstRow(), isInComboBox), + new KeyMapping(new KeyBinding(END).shift(), e -> selectAllToLastRow(), isInComboBox), new KeyMapping(new KeyBinding(PAGE_UP).shift(), e -> selectAllPageUp()), new KeyMapping(new KeyBinding(PAGE_DOWN).shift(), e -> selectAllPageDown()), @@ -98,9 +107,9 @@ public ListViewBehavior(ListView control) { new KeyMapping(F2, e -> activate()), new KeyMapping(ESCAPE, e -> cancelEdit()), - new KeyMapping(new KeyBinding(A).shortcut(), e -> selectAll()), - new KeyMapping(new KeyBinding(HOME).shortcut(), e -> focusFirstRow()), - new KeyMapping(new KeyBinding(END).shortcut(), e -> focusLastRow()), + new KeyMapping(new KeyBinding(A).shortcut(), e -> selectAll(), isInComboBox), + new KeyMapping(new KeyBinding(HOME).shortcut(), e -> focusFirstRow(), isInComboBox), + new KeyMapping(new KeyBinding(END).shortcut(), e -> focusLastRow(), isInComboBox), new KeyMapping(new KeyBinding(PAGE_UP).shortcut(), e -> focusPageUp()), new KeyMapping(new KeyBinding(PAGE_DOWN).shortcut(), e -> focusPageDown()), @@ -145,10 +154,9 @@ public ListViewBehavior(ListView control) { new KeyMapping(new KeyBinding(DOWN).shortcut().shift(), e -> discontinuousSelectNextRow()), new KeyMapping(new KeyBinding(PAGE_UP).shortcut().shift(), e -> discontinuousSelectPageUp()), new KeyMapping(new KeyBinding(PAGE_DOWN).shortcut().shift(), e -> discontinuousSelectPageDown()), - new KeyMapping(new KeyBinding(HOME).shortcut().shift(), e -> discontinuousSelectAllToFirstRow()), - new KeyMapping(new KeyBinding(END).shortcut().shift(), e -> discontinuousSelectAllToLastRow()) + new KeyMapping(new KeyBinding(HOME).shortcut().shift(), e -> discontinuousSelectAllToFirstRow(), isInComboBox), + new KeyMapping(new KeyBinding(END).shortcut().shift(), e -> discontinuousSelectAllToLastRow(), isInComboBox) ); - addDefaultChildMap(listViewInputMap, verticalListInputMap); // --- horizontal listview @@ -198,7 +206,6 @@ public ListViewBehavior(ListView control) { } - /*************************************************************************** * * * Implementation of BehaviorBase API * diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java index 8a40e3e61c..98abe2237e 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java @@ -29,6 +29,7 @@ import com.sun.javafx.scene.control.behavior.ComboBoxListViewBehavior; import java.util.List; +import java.util.function.Supplier; import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; @@ -504,6 +505,9 @@ private void updateCellFactory() { { getProperties().put("selectFirstRowByDefault", false); + // editableComboBox property is used to intercept few Key inputs from this ListView, + // so that those inputs get forwarded to editor of ComboBox . + getProperties().put("editableComboBox", (Supplier) () -> getSkinnable().isEditable()); } @Override protected double computeMinHeight(double width) { diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ComboBoxTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ComboBoxTest.java index 38a10fc400..4bd1c48fbc 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ComboBoxTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ComboBoxTest.java @@ -25,9 +25,16 @@ package test.javafx.scene.control; +import com.sun.javafx.scene.control.behavior.FocusTraversalInputMap; +import com.sun.javafx.scene.control.behavior.ListViewBehavior; +import com.sun.javafx.scene.control.inputmap.InputMap; +import com.sun.javafx.scene.control.inputmap.InputMap.KeyMapping; +import com.sun.javafx.scene.control.inputmap.KeyBinding; +import com.sun.javafx.tk.Toolkit; + +import test.com.sun.javafx.scene.control.infrastructure.ControlSkinFactory; import test.com.sun.javafx.scene.control.infrastructure.KeyModifier; import test.com.sun.javafx.scene.control.infrastructure.MouseEventFirer; -import com.sun.javafx.tk.Toolkit; import javafx.css.PseudoClass; import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer; @@ -1334,6 +1341,244 @@ public void defaultConverterCanHandleIncorrectType_2() { sl.dispose(); } + @Test public void testEditorKeyInputsWhenPopupIsShowing() { + final ComboBox cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c")); + cb.setEditable(true); + StageLoader sl = new StageLoader(cb); + KeyEventFirer keyboard = new KeyEventFirer(cb); + + // Show the popup + assertFalse(cb.isShowing()); + cb.requestFocus(); + cb.getEditor().setText("ABC DEF"); + assertEquals("ABC DEF", cb.getEditor().getText()); + keyboard.doDownArrowPress(KeyModifier.ALT); + // Sanity + assertTrue(cb.isShowing()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // LEFT, RIGHT keys with CTRL, SHIFT modifiers + // Test RIGHT key + keyboard.doRightArrowPress(); + assertEquals(1, cb.getEditor().getCaretPosition()); + + // Test KP_RIGHT key + keyboard.doKeyPress(KeyCode.KP_RIGHT); + assertEquals(2, cb.getEditor().getCaretPosition()); + + // Test LEFT key + keyboard.doLeftArrowPress(); + assertEquals(1, cb.getEditor().getCaretPosition()); + + // Test KP_LEFT key + keyboard.doKeyPress(KeyCode.KP_LEFT); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test SHIFT + RIGHT key + keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); + assertEquals("A", cb.getEditor().getSelectedText()); + assertEquals(1, cb.getEditor().getCaretPosition()); + + // Test SHIFT + LEFT key + keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test CTRL + RIGHT key + keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.CTRL); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(4, cb.getEditor().getCaretPosition()); + + // Test CTRL + LEFT key + keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.CTRL); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test CTRL + SHIFT + RIGHT key + keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.CTRL, KeyModifier.SHIFT); + assertEquals("ABC ", cb.getEditor().getSelectedText()); + assertEquals(4, cb.getEditor().getCaretPosition()); + + // Test CTRL + SHIFT + LEFT key + keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.CTRL, KeyModifier.SHIFT); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // HOME, END keys with CTRL, SHIFT modifiers + // Test END key + keyboard.doKeyPress(KeyCode.END); + assertEquals(7, cb.getEditor().getCaretPosition()); + + // Test HOME key + keyboard.doKeyPress(KeyCode.HOME); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test SHIFT + END key + keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); + assertEquals(cb.getEditor().getText(), cb.getEditor().getSelectedText()); + assertEquals(7, cb.getEditor().getCaretPosition()); + + // Test SHIFT + HOME key + keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test CTRL + END key + keyboard.doKeyPress(KeyCode.END, KeyModifier.CTRL); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(7, cb.getEditor().getCaretPosition()); + + // Test CTRL + HOME key + keyboard.doKeyPress(KeyCode.HOME, KeyModifier.CTRL); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test CTRL + SHIFT + END key + keyboard.doKeyPress(KeyCode.END, KeyModifier.CTRL, KeyModifier.SHIFT); + assertEquals(cb.getEditor().getText(), cb.getEditor().getSelectedText()); + assertEquals(7, cb.getEditor().getCaretPosition()); + + // Test CTRL + SHIFT + HOME key + keyboard.doKeyPress(KeyCode.HOME, KeyModifier.CTRL, KeyModifier.SHIFT); + assertEquals("", cb.getEditor().getSelectedText()); + assertEquals(0, cb.getEditor().getCaretPosition()); + + // Test CTRL + A key + keyboard.doLeftArrowPress(); + assertEquals("", cb.getEditor().getSelectedText()); + keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); + assertEquals(cb.getEditor().getText(), cb.getEditor().getSelectedText()); + + // Sanity + assertTrue(cb.isShowing()); + + sl.dispose(); + } + + @Test public void testKeyInputsOnNonEditableComboBox() { + final ComboBox cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c")); + // cb.setEditable(false); // by default ComboBox is not editable + StageLoader sl = new StageLoader(cb); + SingleSelectionModel sm = cb.getSelectionModel(); + sm.select(0); + KeyEventFirer keyboard = new KeyEventFirer(cb); + + // Show the popup + assertFalse(cb.isShowing()); + cb.requestFocus(); + keyboard.doDownArrowPress(KeyModifier.ALT); + // Sanity + assertTrue(cb.isShowing()); + assertEquals(0, sm.getSelectedIndex()); + + // Test RIGHT key + keyboard.doRightArrowPress(); + assertEquals(0, sm.getSelectedIndex()); + + // Test KP_RIGHT key + keyboard.doKeyPress(KeyCode.KP_RIGHT); + assertEquals(0, sm.getSelectedIndex()); + + // Test DOWN key + keyboard.doDownArrowPress(); + assertEquals(1, sm.getSelectedIndex()); + + // Test KP_DOWN key + keyboard.doKeyPress(KeyCode.KP_DOWN); + assertEquals(2, sm.getSelectedIndex()); + + // Test LEFT key + keyboard.doLeftArrowPress(); + assertEquals(2, sm.getSelectedIndex()); + + // Test KP_LEFT key + keyboard.doKeyPress(KeyCode.KP_LEFT); + assertEquals(2, sm.getSelectedIndex()); + + // Test UP key + keyboard.doUpArrowPress(); + assertEquals(1, sm.getSelectedIndex()); + + // Test KP_UP key + keyboard.doKeyPress(KeyCode.KP_UP); + assertEquals(0, sm.getSelectedIndex()); + + // Test END key + keyboard.doKeyPress(KeyCode.END); + assertEquals(2, sm.getSelectedIndex()); + + // Test HOME key + keyboard.doKeyPress(KeyCode.HOME); + assertEquals(0, sm.getSelectedIndex()); + + // Sanity + assertTrue(cb.isShowing()); + + sl.dispose(); + } + + @Test public void testInterceptedKeyMappingsForComboBoxEditor() { + final ComboBox cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c")); + StageLoader sl = new StageLoader(cb); + + ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent(); + ListViewBehavior lvBehavior = (ListViewBehavior)ControlSkinFactory.getBehavior(listView.getSkin()); + InputMap> lvInputMap = lvBehavior.getInputMap(); + ObservableList inputMappings = lvInputMap.getMappings(); + // In ListViewBehavior KeyMappings for vertical orientation are added under 3rd child InputMap + InputMap> verticalInputMap = lvInputMap.getChildInputMaps().get(2); + ObservableList verticalInputMappings = verticalInputMap.getMappings(); + + cb.setEditable(true); + testKeyMappingsForEditableCB(inputMappings); + testCommonKeyMappings(inputMappings, verticalInputMappings); + + cb.setEditable(false); + testKeyMappingsForNonEditableCB(inputMappings); + testCommonKeyMappings(inputMappings, verticalInputMappings); + + sl.dispose(); + } + + private void testKeyMappingsForEditableCB(ObservableList inputMappings) { + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME), true); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END), true); + } + + private void testKeyMappingsForNonEditableCB(ObservableList inputMappings) { + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME), false); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END), false); + } + + private void testCommonKeyMappings(ObservableList inputMappings, + ObservableList verticalInputMappings) { + // Verify FocusTraversalInputMap + for(InputMap.Mapping mapping : FocusTraversalInputMap.getFocusTraversalMappings()) { + assertFalse(inputMappings.contains(mapping)); + } + + // Verify default InputMap + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME).shift(), true); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END).shift(), true); + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME).shortcut(), true); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END).shortcut(), true); + testInterceptor(inputMappings, new KeyBinding(KeyCode.A).shortcut(), true); + + // Verify vertical child InputMap + testInterceptor(verticalInputMappings, new KeyBinding(KeyCode.HOME).shortcut().shift(), true); + testInterceptor(verticalInputMappings, new KeyBinding(KeyCode.END).shortcut().shift(), true); + } + + private void testInterceptor(ObservableList mappings, KeyBinding binding, boolean isIntercepted) { + int i = mappings.indexOf(new KeyMapping(binding, null)); + if (((KeyMapping)mappings.get(i)).getInterceptor() != null) { + assertEquals(isIntercepted, ((KeyMapping) mappings.get(i)).getInterceptor().test(null)); + } else { + // JDK-8209788 added interceptor for few KeyMappings + fail("Interceptor must not be null"); + } + } + @Test public void test_rt36280_nonEditable_enterHidesShowingPopup() { final ComboBox cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c")); StageLoader sl = new StageLoader(cb); diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java index 57bba4a84e..fd575d5f92 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java @@ -26,7 +26,12 @@ package test.javafx.scene.control; import com.sun.javafx.scene.control.VirtualScrollBar; +import com.sun.javafx.scene.control.behavior.FocusTraversalInputMap; import com.sun.javafx.scene.control.behavior.ListCellBehavior; +import com.sun.javafx.scene.control.behavior.ListViewBehavior; +import com.sun.javafx.scene.control.inputmap.InputMap; +import com.sun.javafx.scene.control.inputmap.InputMap.KeyMapping; +import com.sun.javafx.scene.control.inputmap.KeyBinding; import com.sun.javafx.tk.Toolkit; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -75,6 +80,8 @@ import org.junit.Before; import org.junit.Test; import static test.com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains; + +import test.com.sun.javafx.scene.control.infrastructure.ControlSkinFactory; import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer; import test.com.sun.javafx.scene.control.infrastructure.KeyModifier; import test.com.sun.javafx.scene.control.infrastructure.StageLoader; @@ -171,6 +178,40 @@ assertSame(sm, sm); } + @Test public void testCtrlAWhenSwitchingSelectionModel() { + ListView listView = new ListView<>(); + listView.getItems().addAll("a", "b", "c", "d"); + + MultipleSelectionModel sm; + StageLoader sl = new StageLoader(listView); + KeyEventFirer keyboard = new KeyEventFirer(listView); + + MultipleSelectionModel smMultiple = ListViewShim.getListViewBitSetSelectionModel(listView); + smMultiple.setSelectionMode(SelectionMode.MULTIPLE); + MultipleSelectionModel smSingle = ListViewShim.getListViewBitSetSelectionModel(listView); + smSingle.setSelectionMode(SelectionMode.SINGLE); + + listView.setSelectionModel(smMultiple); + sm = listView.getSelectionModel(); + + assertEquals(0, sm.getSelectedItems().size()); + sm.clearAndSelect(0); + assertEquals(1, sm.getSelectedItems().size()); + keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); + assertEquals(4, sm.getSelectedItems().size()); + + listView.setSelectionModel(smSingle); + sm = listView.getSelectionModel(); + + assertEquals(0, sm.getSelectedItems().size()); + sm.clearAndSelect(0); + assertEquals(1, sm.getSelectedItems().size()); + keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); + assertEquals(1, sm.getSelectedItems().size()); + + sl.dispose(); + } + @Test public void canSetSelectedItemToAnItemEvenWhenThereAreNoItems() { final String randomString = new String("I AM A CRAZY RANDOM STRING"); sm.select(randomString); @@ -1465,6 +1506,33 @@ private void test_rt_39559(boolean useSMSelectAll) { sl.dispose(); } + @Test public void testCtrlAWhenSwitchingSelectionMode() { + ListView listView = new ListView<>(); + listView.getItems().addAll("a", "b", "c", "d"); + + MultipleSelectionModel sm = listView.getSelectionModel(); + StageLoader sl = new StageLoader(listView); + KeyEventFirer keyboard = new KeyEventFirer(listView); + + assertEquals(0, sm.getSelectedItems().size()); + sm.clearAndSelect(0); + assertEquals(1, sm.getSelectedItems().size()); + keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); + assertEquals(1, sm.getSelectedItems().size()); + + sm.setSelectionMode(SelectionMode.MULTIPLE); + assertEquals(1, sm.getSelectedItems().size()); + keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); + assertEquals(4, sm.getSelectedItems().size()); + + sm.setSelectionMode(SelectionMode.SINGLE); + assertEquals(1, sm.getSelectedItems().size()); + keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); + assertEquals(1, sm.getSelectedItems().size()); + + sl.dispose(); + } + @Test public void test_rt_16068_firstElement_selectAndRemoveSameRow() { // select and then remove the 'a' item, selection and focus should both // stay at the first row, now 'b' @@ -1977,6 +2045,49 @@ public void testEventIndicesOnSelectRange() { assertEquals("List item at index 2 should be selected", 2, (int) sm.getSelectedIndices().get(1)); } + @Test public void testInterceptedKeyMappingsForComboBoxEditor() { + ListView listView = new ListView<>(FXCollections + .observableArrayList("Item1", "Item2")); + StageLoader sl = new StageLoader(listView); + + ListViewBehavior lvBehavior = (ListViewBehavior) ControlSkinFactory.getBehavior(listView.getSkin()); + InputMap> lvInputMap = lvBehavior.getInputMap(); + ObservableList inputMappings = lvInputMap.getMappings(); + // In ListViewBehavior KeyMappings for vertical orientation are added under 3rd child InputMap + InputMap> verticalInputMap = lvInputMap.getChildInputMaps().get(2); + ObservableList verticalInputMappings = verticalInputMap.getMappings(); + + // Verify FocusTraversalInputMap + for(InputMap.Mapping mapping : FocusTraversalInputMap.getFocusTraversalMappings()) { + assertTrue(inputMappings.contains(mapping)); + } + + // Verify default InputMap + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME)); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END)); + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME).shift()); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END).shift()); + testInterceptor(inputMappings, new KeyBinding(KeyCode.HOME).shortcut()); + testInterceptor(inputMappings, new KeyBinding(KeyCode.END).shortcut()); + testInterceptor(inputMappings, new KeyBinding(KeyCode.A).shortcut()); + + // Verify vertical child InputMap + testInterceptor(verticalInputMappings, new KeyBinding(KeyCode.HOME).shortcut().shift()); + testInterceptor(verticalInputMappings, new KeyBinding(KeyCode.END).shortcut().shift()); + + sl.dispose(); + } + + private void testInterceptor(ObservableList mappings, KeyBinding binding) { + int i = mappings.indexOf(new KeyMapping(binding, null)); + if (((KeyMapping)mappings.get(i)).getInterceptor() != null) { + assertFalse(((KeyMapping)mappings.get(i)).getInterceptor().test(null)); + } else { + // JDK-8209788 added interceptor for few KeyMappings + fail("Interceptor must not be null"); + } + } + @Test public void testListViewLeak() { ObservableList items = FXCollections.observableArrayList();