modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ListViewBehavior.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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.  Oracle designates this

@@ -20,204 +20,219 @@
  *
  * 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.
  */
-
 package com.sun.javafx.scene.control.behavior;
 
 import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.scene.control.skin.Utils;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.beans.value.WeakChangeListener;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
 import javafx.collections.WeakListChangeListener;
-import javafx.event.EventType;
-import javafx.geometry.NodeOrientation;
+import javafx.event.EventHandler;
 import javafx.geometry.Orientation;
-import javafx.scene.control.Control;
 import javafx.scene.control.FocusModel;
 import javafx.scene.control.ListView;
 import javafx.scene.control.MultipleSelectionModel;
 import javafx.scene.control.SelectionMode;
-import javafx.scene.input.KeyCode;
+import com.sun.javafx.scene.control.inputmap.InputMap;
+import com.sun.javafx.scene.control.inputmap.KeyBinding;
 import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.util.Callback;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.sun.javafx.scene.control.inputmap.InputMap.*;
 import static javafx.scene.input.KeyCode.*;
 
-/**
- *
- */
 public class ListViewBehavior<T> extends BehaviorBase<ListView<T>> {
+    private final InputMap<ListView<T>> listViewInputMap;
 
-    /**************************************************************************
-     *                          Setup KeyBindings                             *
-     *************************************************************************/
-    protected static final List<KeyBinding> LIST_VIEW_BINDINGS = new ArrayList<KeyBinding>();
-
-    static {
-        LIST_VIEW_BINDINGS.add(new KeyBinding(HOME, "SelectFirstRow"));
-        LIST_VIEW_BINDINGS.add(new KeyBinding(END, "SelectLastRow"));
-        LIST_VIEW_BINDINGS.add(new KeyBinding(HOME, "SelectAllToFirstRow").shift());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(END, "SelectAllToLastRow").shift());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_UP, "SelectAllPageUp").shift());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_DOWN, "SelectAllPageDown").shift());
-        
-        LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "SelectAllToFocus").shift());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "SelectAllToFocusAndSetAnchor").shortcut().shift());
-        
-        LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_UP, "ScrollUp"));
-        LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_DOWN, "ScrollDown"));
-
-        LIST_VIEW_BINDINGS.add(new KeyBinding(ENTER, "Activate"));
-        LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "Activate"));
-        LIST_VIEW_BINDINGS.add(new KeyBinding(F2, "Activate"));
-        LIST_VIEW_BINDINGS.add(new KeyBinding(ESCAPE, "CancelEdit"));
-
-        LIST_VIEW_BINDINGS.add(new KeyBinding(A, "SelectAll").shortcut());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(HOME, "FocusFirstRow").shortcut());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(END, "FocusLastRow").shortcut());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_UP, "FocusPageUp").shortcut());
-        LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_DOWN, "FocusPageDown").shortcut());
+    /**
+     * Indicates that a keyboard key has been pressed which represents the
+     * event (this could be space bar for example). As long as keyDown is true,
+     * we are also armed, and will ignore mouse events related to arming.
+     * Note this is made package private solely for the sake of testing.
+     */
+    private boolean keyDown;
             
-        if (PlatformUtil.isMac()) {
-            LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "toggleFocusOwnerSelection").ctrl().shortcut());
-        } else {
-            LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "toggleFocusOwnerSelection").ctrl());
+    private final EventHandler<KeyEvent> keyEventListener = e -> {
+        if (!e.isConsumed()) {
+            // RT-12751: we want to keep an eye on the user holding down the shift key,
+            // so that we know when they enter/leave multiple selection mode. This
+            // changes what happens when certain key combinations are pressed.
+            isShiftDown = e.getEventType() == KeyEvent.KEY_PRESSED && e.isShiftDown();
+            isShortcutDown = e.getEventType() == KeyEvent.KEY_PRESSED && e.isShortcutDown();
         }
-
-        // if listView is vertical...
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(UP, "SelectPreviousRow").vertical());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_UP, "SelectPreviousRow").vertical());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(DOWN, "SelectNextRow").vertical());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_DOWN, "SelectNextRow").vertical());
-
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(UP, "AlsoSelectPreviousRow").vertical().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_UP, "AlsoSelectPreviousRow").vertical().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(DOWN, "AlsoSelectNextRow").vertical().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_DOWN, "AlsoSelectNextRow").vertical().shift());
-
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(UP, "FocusPreviousRow").vertical().shortcut());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(DOWN, "FocusNextRow").vertical().shortcut());
-
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(UP, "DiscontinuousSelectPreviousRow").vertical().shortcut().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(DOWN, "DiscontinuousSelectNextRow").vertical().shortcut().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(PAGE_UP, "DiscontinuousSelectPageUp").vertical().shortcut().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(PAGE_DOWN, "DiscontinuousSelectPageDown").vertical().shortcut().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(HOME, "DiscontinuousSelectAllToFirstRow").vertical().shortcut().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(END, "DiscontinuousSelectAllToLastRow").vertical().shortcut().shift());
-        // --- end of vertical
+    };
 
 
 
-        // if listView is horizontal...
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(LEFT, "SelectPreviousRow"));
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_LEFT, "SelectPreviousRow"));
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(RIGHT, "SelectNextRow"));
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_RIGHT, "SelectNextRow"));
+    /***************************************************************************
+     *                                                                         *
+     * Constructors                                                            *
+     *                                                                         *
+     **************************************************************************/
 
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(LEFT, "AlsoSelectPreviousRow").shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_LEFT, "AlsoSelectPreviousRow").shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(RIGHT, "AlsoSelectNextRow").shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(KP_RIGHT, "AlsoSelectNextRow").shift());
+    public ListViewBehavior(ListView<T> control) {
+        super(control);
 
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(LEFT, "FocusPreviousRow").shortcut());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(RIGHT, "FocusNextRow").shortcut());
+        // create a map for listView-specific mappings
+        listViewInputMap = createInputMap();
 
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(LEFT, "DiscontinuousSelectPreviousRow").shortcut().shift());
-        LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(RIGHT, "DiscontinuousSelectNextRow").shortcut().shift());
-        // --- end of horizontal
+        // add focus traversal mappings
+        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(PAGE_UP).shift(), e -> selectAllPageUp()),
+            new KeyMapping(new KeyBinding(PAGE_DOWN).shift(), e -> selectAllPageDown()),
+
+            new KeyMapping(new KeyBinding(SPACE).shift(), e -> selectAllToFocus(false)),
+            new KeyMapping(new KeyBinding(SPACE).shortcut().shift(), e -> selectAllToFocus(true)),
+
+            new KeyMapping(PAGE_UP, e -> scrollPageUp()),
+            new KeyMapping(PAGE_DOWN, e -> scrollPageDown()),
+
+            new KeyMapping(ENTER, e -> activate()),
+            new KeyMapping(SPACE, e -> activate()),
+            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(PAGE_UP).shortcut(), e -> focusPageUp()),
+            new KeyMapping(new KeyBinding(PAGE_DOWN).shortcut(), e -> focusPageDown()),
+
+            new KeyMapping(new KeyBinding(BACK_SLASH).shortcut(), e -> clearSelection()),
+
+            new MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed)
+        );
+
+        // create OS-specific child mappings
+        // --- mac OS
+        InputMap<ListView<T>> macInputMap = new InputMap<>(control);
+        macInputMap.setInterceptor(event -> !PlatformUtil.isMac());
+        addDefaultMapping(macInputMap, new KeyMapping(new KeyBinding(SPACE).shortcut().ctrl(), e -> toggleFocusOwnerSelection()));
+        addDefaultChildMap(listViewInputMap, macInputMap);
+
+        // --- all other platforms
+        InputMap<ListView<T>> otherOsInputMap = new InputMap<>(control);
+        otherOsInputMap.setInterceptor(event -> PlatformUtil.isMac());
+        addDefaultMapping(otherOsInputMap, new KeyMapping(new KeyBinding(SPACE).ctrl(), e -> toggleFocusOwnerSelection()));
+        addDefaultChildMap(listViewInputMap, otherOsInputMap);
+
+        // create two more child maps, one for vertical listview and one for horizontal listview
+        // --- vertical listview
+        InputMap<ListView<T>> verticalListInputMap = new InputMap<>(control);
+        verticalListInputMap.setInterceptor(event -> control.getOrientation() != Orientation.VERTICAL);
+
+        addDefaultMapping(verticalListInputMap,
+            new KeyMapping(UP, e -> selectPreviousRow()),
+            new KeyMapping(KP_UP, e -> selectPreviousRow()),
+            new KeyMapping(DOWN, e -> selectNextRow()),
+            new KeyMapping(KP_DOWN, e -> selectNextRow()),
+
+            new KeyMapping(new KeyBinding(UP).shift(), e -> alsoSelectPreviousRow()),
+            new KeyMapping(new KeyBinding(KP_UP).shift(), e -> alsoSelectPreviousRow()),
+            new KeyMapping(new KeyBinding(DOWN).shift(), e -> alsoSelectNextRow()),
+            new KeyMapping(new KeyBinding(KP_DOWN).shift(), e -> alsoSelectNextRow()),
+
+            new KeyMapping(new KeyBinding(UP).shortcut(), e -> focusPreviousRow()),
+            new KeyMapping(new KeyBinding(DOWN).shortcut(), e -> focusNextRow()),
+
+            new KeyMapping(new KeyBinding(UP).shortcut().shift(), e -> discontinuousSelectPreviousRow()),
+            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())
+        );
+
+        addDefaultChildMap(listViewInputMap, verticalListInputMap);
+
+        // --- horizontal listview
+        InputMap<ListView<T>> horizontalListInputMap = new InputMap<>(control);
+        horizontalListInputMap.setInterceptor(event -> control.getOrientation() != Orientation.HORIZONTAL);
+
+        addDefaultMapping(horizontalListInputMap,
+            new KeyMapping(LEFT, e -> selectPreviousRow()),
+            new KeyMapping(KP_LEFT, e -> selectPreviousRow()),
+            new KeyMapping(RIGHT, e -> selectNextRow()),
+            new KeyMapping(KP_RIGHT, e -> selectNextRow()),
+
+            new KeyMapping(new KeyBinding(LEFT).shift(), e -> alsoSelectPreviousRow()),
+            new KeyMapping(new KeyBinding(KP_LEFT).shift(), e -> alsoSelectPreviousRow()),
+            new KeyMapping(new KeyBinding(RIGHT).shift(), e -> alsoSelectNextRow()),
+            new KeyMapping(new KeyBinding(KP_RIGHT).shift(), e -> alsoSelectNextRow()),
+
+            new KeyMapping(new KeyBinding(LEFT).shortcut(), e -> focusPreviousRow()),
+            new KeyMapping(new KeyBinding(RIGHT).shortcut(), e -> focusNextRow()),
+
+            new KeyMapping(new KeyBinding(LEFT).shortcut().shift(), e -> discontinuousSelectPreviousRow()),
+            new KeyMapping(new KeyBinding(RIGHT).shortcut().shift(), e -> discontinuousSelectNextRow())
+        );
+
+        addDefaultChildMap(listViewInputMap, horizontalListInputMap);
+
+        // set up other listeners
+        // We make this an event _filter_ so that we can determine the state
+        // of the shift key before the event handlers get a shot at the event.
+        control.addEventFilter(KeyEvent.ANY, keyEventListener);
 
-        LIST_VIEW_BINDINGS.add(new KeyBinding(BACK_SLASH, "ClearSelection").shortcut());
+        control.itemsProperty().addListener(weakItemsListener);
+        if (control.getItems() != null) {
+            control.getItems().addListener(weakItemsListListener);
     }
     
-    protected /*final*/ String matchActionForEvent(KeyEvent e) {
-        String action = super.matchActionForEvent(e);
-        if (action != null) {
-            if (e.getCode() == LEFT || e.getCode() == KP_LEFT) {
-                if (getControl().getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT) {
-                    if (e.isShiftDown()) {
-                        action = "AlsoSelectNextRow";
-                    } else {
-                        if (e.isShortcutDown()) {
-                            action = "FocusNextRow";
-                        } else {
-                            action = getControl().getOrientation() == Orientation.HORIZONTAL ? "SelectNextRow" : "TraverseRight";
-                        }
-                    }
-                }
-            } else if (e.getCode() == RIGHT || e.getCode() == KP_RIGHT) {
-                if (getControl().getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT) {
-                    if (e.isShiftDown()) {
-                        action = "AlsoSelectPreviousRow";
-                    } else {
-                        if (e.isShortcutDown()) {
-                            action = "FocusPreviousRow";
-                        } else {
-                            action = getControl().getOrientation() == Orientation.HORIZONTAL ? "SelectPreviousRow" : "TraverseLeft";
-                        }
-                    }
-                }
+        // Fix for RT-16565
+        control.selectionModelProperty().addListener(weakSelectionModelListener);
+        if (control.getSelectionModel() != null) {
+            control.getSelectionModel().getSelectedIndices().addListener(weakSelectedIndicesListener);
             }
+
+        // Only add this if we're on an embedded platform that supports 5-button navigation
+        if (Utils.isTwoLevelFocus()) {
+            tlFocus = new TwoLevelFocusListBehavior(control); // needs to be last.
         }
-        return action;
     }
 
-    @Override protected void callAction(String name) {
-        if ("SelectPreviousRow".equals(name)) selectPreviousRow();
-        else if ("SelectNextRow".equals(name)) selectNextRow();
-        else if ("SelectFirstRow".equals(name)) selectFirstRow();
-        else if ("SelectLastRow".equals(name)) selectLastRow();
-        else if ("SelectAllToFirstRow".equals(name)) selectAllToFirstRow();
-        else if ("SelectAllToLastRow".equals(name)) selectAllToLastRow();
-        else if ("SelectAllPageUp".equals(name)) selectAllPageUp();
-        else if ("SelectAllPageDown".equals(name)) selectAllPageDown();
-        else if ("AlsoSelectNextRow".equals(name)) alsoSelectNextRow();
-        else if ("AlsoSelectPreviousRow".equals(name)) alsoSelectPreviousRow();
-        else if ("ClearSelection".equals(name)) clearSelection();
-        else if ("SelectAll".equals(name)) selectAll();
-        else if ("ScrollUp".equals(name)) scrollPageUp();
-        else if ("ScrollDown".equals(name)) scrollPageDown();
-        else if ("FocusPreviousRow".equals(name)) focusPreviousRow();
-        else if ("FocusNextRow".equals(name)) focusNextRow();
-        else if ("FocusPageUp".equals(name)) focusPageUp();
-        else if ("FocusPageDown".equals(name)) focusPageDown();
-        else if ("Activate".equals(name)) activate();
-        else if ("CancelEdit".equals(name)) cancelEdit();
-        else if ("FocusFirstRow".equals(name)) focusFirstRow();
-        else if ("FocusLastRow".equals(name)) focusLastRow();
-        else if ("toggleFocusOwnerSelection".equals(name)) toggleFocusOwnerSelection();
-
-        else if ("SelectAllToFocus".equals(name)) selectAllToFocus(false);
-        else if ("SelectAllToFocusAndSetAnchor".equals(name)) selectAllToFocus(true);
-
-        else if ("DiscontinuousSelectNextRow".equals(name)) discontinuousSelectNextRow();
-        else if ("DiscontinuousSelectPreviousRow".equals(name)) discontinuousSelectPreviousRow();
-        else if ("DiscontinuousSelectPageUp".equals(name)) discontinuousSelectPageUp();
-        else if ("DiscontinuousSelectPageDown".equals(name)) discontinuousSelectPageDown();
-        else if ("DiscontinuousSelectAllToLastRow".equals(name)) discontinuousSelectAllToLastRow();
-        else if ("DiscontinuousSelectAllToFirstRow".equals(name)) discontinuousSelectAllToFirstRow();
-        else super.callAction(name);
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Implementation of BehaviorBase API                                      *
+     *                                                                         *
+     **************************************************************************/
+
+    @Override public InputMap<ListView<T>> getInputMap() {
+        return listViewInputMap;
     }
 
-    @Override protected void callActionForEvent(KeyEvent e) {
-        // RT-12751: we want to keep an eye on the user holding down the shift key, 
-        // so that we know when they enter/leave multiple selection mode. This
-        // changes what happens when certain key combinations are pressed.
-        isShiftDown = e.getEventType() == KeyEvent.KEY_PRESSED && e.isShiftDown();
-        isShortcutDown = e.getEventType() == KeyEvent.KEY_PRESSED && e.isShortcutDown();
+    @Override public void dispose() {
+        ListView<T> control = getNode();
 
-        super.callActionForEvent(e);
+        ListCellBehavior.removeAnchor(control);
+        if (tlFocus != null) tlFocus.dispose();
+        super.dispose();
+
+        control.removeEventHandler(KeyEvent.ANY, keyEventListener);
     }
 
+
+
+
+
     /**************************************************************************
      *                         State and Functions                            *
      *************************************************************************/
     
     private boolean isShiftDown = false;

@@ -244,18 +259,18 @@
     private boolean selectionChanging = false;
     
     private final ListChangeListener<Integer> selectedIndicesListener = c -> {
         while (c.next()) {
             if (c.wasReplaced()) {
-                if (ListCellBehavior.hasDefaultAnchor(getControl())) {
-                    ListCellBehavior.removeAnchor(getControl());
+                if (ListCellBehavior.hasDefaultAnchor(getNode())) {
+                    ListCellBehavior.removeAnchor(getNode());
                 }
             }
 
             final int shift = c.wasPermutated() ? c.getTo() - c.getFrom() : 0;
 
-            MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+            MultipleSelectionModel<T> sm = getNode().getSelectionModel();
 
             // there are no selected items, so lets clear out the anchor
             if (! selectionChanging) {
                 if (sm.isEmpty()) {
                     setAnchor(-1);

@@ -319,77 +334,49 @@
     private final WeakChangeListener<MultipleSelectionModel<T>> weakSelectionModelListener = 
             new WeakChangeListener<MultipleSelectionModel<T>>(selectionModelListener);
     
     private TwoLevelFocusListBehavior tlFocus;
 
-    public ListViewBehavior(ListView<T> control) {
-        super(control, LIST_VIEW_BINDINGS);
-        
-        control.itemsProperty().addListener(weakItemsListener);
-        if (control.getItems() != null) {
-            control.getItems().addListener(weakItemsListListener);
-        }
-        
-        // Fix for RT-16565
-        getControl().selectionModelProperty().addListener(weakSelectionModelListener);
-        if (control.getSelectionModel() != null) {
-            control.getSelectionModel().getSelectedIndices().addListener(weakSelectedIndicesListener);
-        }
-
-        // Only add this if we're on an embedded platform that supports 5-button navigation
-        if (Utils.isTwoLevelFocus()) {
-            tlFocus = new TwoLevelFocusListBehavior(control); // needs to be last.
-        }
-    }
-    
-    @Override public void dispose() {
-        ListCellBehavior.removeAnchor(getControl());
-        if (tlFocus != null) tlFocus.dispose();
-        super.dispose();
-    }
-
     private void setAnchor(int anchor) {
-        ListCellBehavior.setAnchor(getControl(), anchor < 0 ? null : anchor, false);
+        ListCellBehavior.setAnchor(getNode(), anchor < 0 ? null : anchor, false);
     }
     
     private int getAnchor() {
-        return ListCellBehavior.getAnchor(getControl(), getControl().getFocusModel().getFocusedIndex());
+        return ListCellBehavior.getAnchor(getNode(), getNode().getFocusModel().getFocusedIndex());
     }
     
     private boolean hasAnchor() {
-        return ListCellBehavior.hasNonDefaultAnchor(getControl());
+        return ListCellBehavior.hasNonDefaultAnchor(getNode());
     }
 
-    @Override public void mousePressed(MouseEvent e) {
-        super.mousePressed(e);
-        
+    private void mousePressed(MouseEvent e) {
         if (! e.isShiftDown() && ! e.isSynthesized()) {
-            int index = getControl().getSelectionModel().getSelectedIndex();
+            int index = getNode().getSelectionModel().getSelectedIndex();
             setAnchor(index);
         }
         
-        if (! getControl().isFocused() && getControl().isFocusTraversable()) {
-            getControl().requestFocus();
+        if (! getNode().isFocused() && getNode().isFocusTraversable()) {
+            getNode().requestFocus();
         }
     }
     
     private int getRowCount() {
-        return getControl().getItems() == null ? 0 : getControl().getItems().size();
+        return getNode().getItems() == null ? 0 : getNode().getItems().size();
     }
 
     private void clearSelection() {
-        getControl().getSelectionModel().clearSelection();
+        getNode().getSelectionModel().clearSelection();
     }
 
     private void scrollPageUp() {
         int newSelectedIndex = -1;
         if (onScrollPageUp != null) {
             newSelectedIndex = onScrollPageUp.call(false);
         }
         if (newSelectedIndex == -1) return;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         sm.clearAndSelect(newSelectedIndex);
     }
 
     private void scrollPageDown() {

@@ -397,36 +384,36 @@
         if (onScrollPageDown != null) {
             newSelectedIndex = onScrollPageDown.call(false);
         }
         if (newSelectedIndex == -1) return;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         sm.clearAndSelect(newSelectedIndex);
     }
     
     private void focusFirstRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         fm.focus(0);
         
         if (onMoveToFirstCell != null) onMoveToFirstCell.run();
     }
     
     private void focusLastRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         fm.focus(getRowCount() - 1);
         
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
 
     private void focusPreviousRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
         fm.focusPrevious();
         
         if (! isShortcutDown || getAnchor() == -1) {

@@ -435,14 +422,14 @@
         
         if (onFocusPreviousRow != null) onFocusPreviousRow.run();
     }
 
     private void focusNextRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
         fm.focusNext();
         
         if (! isShortcutDown || getAnchor() == -1) {

@@ -453,28 +440,28 @@
     }
     
     private void focusPageUp() {
         int newFocusIndex = onScrollPageUp.call(true);
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         fm.focus(newFocusIndex);
     }
     
     private void focusPageDown() {
         int newFocusIndex = onScrollPageDown.call(true);
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         fm.focus(newFocusIndex);
     }
 
     private void alsoSelectPreviousRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
         if (isShiftDown && getAnchor() != -1) {
             int newRow = fm.getFocusedIndex() - 1;
             if (newRow < 0) return;

@@ -500,14 +487,14 @@
         
         onSelectPreviousRow.run();
     }
 
     private void alsoSelectNextRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
         if (isShiftDown && getAnchor() != -1) {
             int newRow = fm.getFocusedIndex() + 1;
             int anchor = getAnchor();

@@ -531,11 +518,11 @@
         
         onSelectNextRow.run();
     }
     
     private void clearSelectionOutsideRange(int start, int end) {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
         int min = Math.min(start, end);
         int max = Math.max(start, end);
         

@@ -550,25 +537,25 @@
         }
         selectionChanging = false;
     }
 
     private void selectPreviousRow() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int focusIndex = fm.getFocusedIndex();
         if (focusIndex <= 0) {
             return;
         }
 
         setAnchor(focusIndex - 1);
-        getControl().getSelectionModel().clearAndSelect(focusIndex - 1);
+        getNode().getSelectionModel().clearAndSelect(focusIndex - 1);
         onSelectPreviousRow.run();
     }
 
     private void selectNextRow() {
-        ListView<T> listView = getControl();
+        ListView<T> listView = getNode();
         FocusModel<T> fm = listView.getFocusModel();
         if (fm == null) return;
         
         int focusIndex = fm.getFocusedIndex();
         if (focusIndex == getRowCount() - 1) {

@@ -583,22 +570,22 @@
         if (onSelectNextRow != null) onSelectNextRow.run();
     }
 
     private void selectFirstRow() {
         if (getRowCount() > 0) {
-            getControl().getSelectionModel().clearAndSelect(0);
+            getNode().getSelectionModel().clearAndSelect(0);
             if (onMoveToFirstCell != null) onMoveToFirstCell.run();
         }
     }
 
     private void selectLastRow() {
-        getControl().getSelectionModel().clearAndSelect(getRowCount() - 1);
+        getNode().getSelectionModel().clearAndSelect(getRowCount() - 1);
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
     
     private void selectAllPageUp() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int leadIndex = fm.getFocusedIndex();
         if (isShiftDown) {
             leadIndex = getAnchor() == -1 ? leadIndex : getAnchor();

@@ -608,11 +595,11 @@
         int leadSelectedIndex = onScrollPageUp.call(false);
 
         // fix for RT-34407
         int adjust = leadIndex < leadSelectedIndex ? 1 : -1;
 
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
         selectionChanging = true;
         if (sm.getSelectionMode() == SelectionMode.SINGLE) {
             sm.select(leadSelectedIndex);

@@ -622,11 +609,11 @@
         }
         selectionChanging = false;
     }
     
     private void selectAllPageDown() {
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
         int leadIndex = fm.getFocusedIndex();
         if (isShiftDown) {
             leadIndex = getAnchor() == -1 ? leadIndex : getAnchor();

@@ -636,11 +623,11 @@
         int leadSelectedIndex = onScrollPageDown.call(false);
 
         // fix for RT-34407
         int adjust = leadIndex < leadSelectedIndex ? 1 : -1;
         
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
         selectionChanging = true;
         if (sm.getSelectionMode() == SelectionMode.SINGLE) {
             sm.select(leadSelectedIndex);

@@ -650,14 +637,14 @@
         }
         selectionChanging = false;
     }
 
     private void selectAllToFirstRow() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
         int leadIndex = fm.getFocusedIndex();
         
         if (isShiftDown) {

@@ -676,18 +663,19 @@
         
         if (onMoveToFirstCell != null) onMoveToFirstCell.run();
     }
 
     private void selectAllToLastRow() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int leadIndex = fm.getFocusedIndex();
 
+        System.out.println("isShiftDown: " + isShiftDown);
         if (isShiftDown) {
             leadIndex = hasAnchor() ? getAnchor() : leadIndex;
         }
         
         sm.clearSelection();

@@ -699,18 +687,18 @@
 
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
 
     private void selectAll() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         sm.selectAll();
     }
     
     private void selectAllToFocus(boolean setAnchorToFocusIndex) {
         // Fix for RT-31241
-        final ListView<T> listView = getControl();
+        final ListView<T> listView = getNode();
         if (listView.getEditingIndex() >= 0) return;
 
         MultipleSelectionModel<T> sm = listView.getSelectionModel();
         if (sm == null) return;
 

@@ -726,29 +714,29 @@
         sm.selectRange(startPos, endPos);
         setAnchor(setAnchorToFocusIndex ? focusIndex : anchor);
     }
     
     private void cancelEdit() {
-        getControl().edit(-1);
+        getNode().edit(-1);
     }
 
     private void activate() {
-        int focusedIndex = getControl().getFocusModel().getFocusedIndex();
-        getControl().getSelectionModel().select(focusedIndex);
+        int focusedIndex = getNode().getFocusModel().getFocusedIndex();
+        getNode().getSelectionModel().select(focusedIndex);
         setAnchor(focusedIndex);
 
         // edit this row also
         if (focusedIndex >= 0) {
-            getControl().edit(focusedIndex);
+            getNode().edit(focusedIndex);
         }
     }
     
     private void toggleFocusOwnerSelection() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int focusedIndex = fm.getFocusedIndex();
         
         if (sm.isSelected(focusedIndex)) {

@@ -764,19 +752,19 @@
     /**************************************************************************
      * Discontinuous Selection                                                *
      *************************************************************************/
     
     private void discontinuousSelectPreviousRow() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
         if (sm.getSelectionMode() != SelectionMode.MULTIPLE) {
             selectPreviousRow();
             return;
         }
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
         int focusIndex = fm.getFocusedIndex();
         final int newFocusIndex = focusIndex - 1;
         if (newFocusIndex < 0) return;

@@ -791,19 +779,19 @@
 
         if (onFocusPreviousRow != null) onFocusPreviousRow.run();
     }
     
     private void discontinuousSelectNextRow() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
         if (sm.getSelectionMode() != SelectionMode.MULTIPLE) {
             selectNextRow();
             return;
         }
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int focusIndex = fm.getFocusedIndex();
         final int newFocusIndex = focusIndex + 1;
         if (newFocusIndex >= getRowCount()) return;

@@ -818,71 +806,55 @@
 
         if (onFocusNextRow != null) onFocusNextRow.run();
     }
     
     private void discontinuousSelectPageUp() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int anchor = getAnchor();
         int leadSelectedIndex = onScrollPageUp.call(false);
         sm.selectRange(anchor, leadSelectedIndex - 1);
     }
     
     private void discontinuousSelectPageDown() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
         
         int anchor = getAnchor();
         int leadSelectedIndex = onScrollPageDown.call(false);
         sm.selectRange(anchor, leadSelectedIndex + 1);
     }
     
     private void discontinuousSelectAllToFirstRow() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int index = fm.getFocusedIndex();
         sm.selectRange(0, index);
         fm.focus(0);
 
         if (onMoveToFirstCell != null) onMoveToFirstCell.run();
     }
     
     private void discontinuousSelectAllToLastRow() {
-        MultipleSelectionModel<T> sm = getControl().getSelectionModel();
+        MultipleSelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
         
-        FocusModel<T> fm = getControl().getFocusModel();
+        FocusModel<T> fm = getNode().getFocusModel();
         if (fm == null) return;
 
         int index = fm.getFocusedIndex() + 1;
         sm.selectRange(index, getRowCount());
 
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
-
-    private static class ListViewKeyBinding extends OrientedKeyBinding {
-
-        public ListViewKeyBinding(KeyCode code, String action) {
-            super(code, action);
-        }
-
-        public ListViewKeyBinding(KeyCode code, EventType<KeyEvent> type, String action) {
-            super(code, type, action);
-        }
-
-        @Override public boolean getVertical(Control control) {
-            return ((ListView<?>)control).getOrientation() == Orientation.VERTICAL;
-        }
-    }
-
 }