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 ****
/*
! * Copyright (c) 2010, 2014, 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
--- 1,7 ----
/*
! * 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,223 ****
*
* 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.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 javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.util.Callback;
import java.util.ArrayList;
import java.util.List;
import static javafx.scene.input.KeyCode.*;
- /**
- *
- */
public class ListViewBehavior<T> extends BehaviorBase<ListView<T>> {
! /**************************************************************************
! * 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());
! if (PlatformUtil.isMac()) {
! LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "toggleFocusOwnerSelection").ctrl().shortcut());
! } else {
! LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "toggleFocusOwnerSelection").ctrl());
}
!
! // 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"));
! 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());
! LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(LEFT, "FocusPreviousRow").shortcut());
! LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(RIGHT, "FocusNextRow").shortcut());
! LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(LEFT, "DiscontinuousSelectPreviousRow").shortcut().shift());
! LIST_VIEW_BINDINGS.add(new ListViewKeyBinding(RIGHT, "DiscontinuousSelectNextRow").shortcut().shift());
! // --- end of horizontal
! LIST_VIEW_BINDINGS.add(new KeyBinding(BACK_SLASH, "ClearSelection").shortcut());
}
! 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";
! }
! }
! }
}
}
- 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);
}
! @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();
! super.callActionForEvent(e);
}
/**************************************************************************
* State and Functions *
*************************************************************************/
private boolean isShiftDown = false;
--- 20,238 ----
*
* 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.EventHandler;
import javafx.geometry.Orientation;
import javafx.scene.control.FocusModel;
import javafx.scene.control.ListView;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.SelectionMode;
! 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;
! /**
! * 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;
! 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();
}
! };
! /***************************************************************************
! * *
! * Constructors *
! * *
! **************************************************************************/
! public ListViewBehavior(ListView<T> control) {
! super(control);
! // create a map for listView-specific mappings
! listViewInputMap = createInputMap();
! // 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);
! control.itemsProperty().addListener(weakItemsListener);
! if (control.getItems() != null) {
! control.getItems().addListener(weakItemsListListener);
}
! // 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.
}
}
!
!
! /***************************************************************************
! * *
! * Implementation of BehaviorBase API *
! * *
! **************************************************************************/
!
! @Override public InputMap<ListView<T>> getInputMap() {
! return listViewInputMap;
}
! @Override public void dispose() {
! ListView<T> control = getNode();
! ListCellBehavior.removeAnchor(control);
! if (tlFocus != null) tlFocus.dispose();
! super.dispose();
!
! control.removeEventHandler(KeyEvent.ANY, keyEventListener);
}
+
+
+
+
/**************************************************************************
* State and Functions *
*************************************************************************/
private boolean isShiftDown = false;
*** 244,261 ****
private boolean selectionChanging = false;
private final ListChangeListener<Integer> selectedIndicesListener = c -> {
while (c.next()) {
if (c.wasReplaced()) {
! if (ListCellBehavior.hasDefaultAnchor(getControl())) {
! ListCellBehavior.removeAnchor(getControl());
}
}
final int shift = c.wasPermutated() ? c.getTo() - c.getFrom() : 0;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
// there are no selected items, so lets clear out the anchor
if (! selectionChanging) {
if (sm.isEmpty()) {
setAnchor(-1);
--- 259,276 ----
private boolean selectionChanging = false;
private final ListChangeListener<Integer> selectedIndicesListener = c -> {
while (c.next()) {
if (c.wasReplaced()) {
! if (ListCellBehavior.hasDefaultAnchor(getNode())) {
! ListCellBehavior.removeAnchor(getNode());
}
}
final int shift = c.wasPermutated() ? c.getTo() - c.getFrom() : 0;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
// there are no selected items, so lets clear out the anchor
if (! selectionChanging) {
if (sm.isEmpty()) {
setAnchor(-1);
*** 319,395 ****
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);
}
private int getAnchor() {
! return ListCellBehavior.getAnchor(getControl(), getControl().getFocusModel().getFocusedIndex());
}
private boolean hasAnchor() {
! return ListCellBehavior.hasNonDefaultAnchor(getControl());
}
! @Override public void mousePressed(MouseEvent e) {
! super.mousePressed(e);
!
if (! e.isShiftDown() && ! e.isSynthesized()) {
! int index = getControl().getSelectionModel().getSelectedIndex();
setAnchor(index);
}
! if (! getControl().isFocused() && getControl().isFocusTraversable()) {
! getControl().requestFocus();
}
}
private int getRowCount() {
! return getControl().getItems() == null ? 0 : getControl().getItems().size();
}
private void clearSelection() {
! getControl().getSelectionModel().clearSelection();
}
private void scrollPageUp() {
int newSelectedIndex = -1;
if (onScrollPageUp != null) {
newSelectedIndex = onScrollPageUp.call(false);
}
if (newSelectedIndex == -1) return;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
sm.clearAndSelect(newSelectedIndex);
}
private void scrollPageDown() {
--- 334,382 ----
private final WeakChangeListener<MultipleSelectionModel<T>> weakSelectionModelListener =
new WeakChangeListener<MultipleSelectionModel<T>>(selectionModelListener);
private TwoLevelFocusListBehavior tlFocus;
private void setAnchor(int anchor) {
! ListCellBehavior.setAnchor(getNode(), anchor < 0 ? null : anchor, false);
}
private int getAnchor() {
! return ListCellBehavior.getAnchor(getNode(), getNode().getFocusModel().getFocusedIndex());
}
private boolean hasAnchor() {
! return ListCellBehavior.hasNonDefaultAnchor(getNode());
}
! private void mousePressed(MouseEvent e) {
if (! e.isShiftDown() && ! e.isSynthesized()) {
! int index = getNode().getSelectionModel().getSelectedIndex();
setAnchor(index);
}
! if (! getNode().isFocused() && getNode().isFocusTraversable()) {
! getNode().requestFocus();
}
}
private int getRowCount() {
! return getNode().getItems() == null ? 0 : getNode().getItems().size();
}
private void clearSelection() {
! getNode().getSelectionModel().clearSelection();
}
private void scrollPageUp() {
int newSelectedIndex = -1;
if (onScrollPageUp != null) {
newSelectedIndex = onScrollPageUp.call(false);
}
if (newSelectedIndex == -1) return;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
sm.clearAndSelect(newSelectedIndex);
}
private void scrollPageDown() {
*** 397,432 ****
if (onScrollPageDown != null) {
newSelectedIndex = onScrollPageDown.call(false);
}
if (newSelectedIndex == -1) return;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
sm.clearAndSelect(newSelectedIndex);
}
private void focusFirstRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
fm.focus(0);
if (onMoveToFirstCell != null) onMoveToFirstCell.run();
}
private void focusLastRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
fm.focus(getRowCount() - 1);
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
private void focusPreviousRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
fm.focusPrevious();
if (! isShortcutDown || getAnchor() == -1) {
--- 384,419 ----
if (onScrollPageDown != null) {
newSelectedIndex = onScrollPageDown.call(false);
}
if (newSelectedIndex == -1) return;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
sm.clearAndSelect(newSelectedIndex);
}
private void focusFirstRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
fm.focus(0);
if (onMoveToFirstCell != null) onMoveToFirstCell.run();
}
private void focusLastRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
fm.focus(getRowCount() - 1);
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
private void focusPreviousRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
fm.focusPrevious();
if (! isShortcutDown || getAnchor() == -1) {
*** 435,448 ****
if (onFocusPreviousRow != null) onFocusPreviousRow.run();
}
private void focusNextRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
fm.focusNext();
if (! isShortcutDown || getAnchor() == -1) {
--- 422,435 ----
if (onFocusPreviousRow != null) onFocusPreviousRow.run();
}
private void focusNextRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
fm.focusNext();
if (! isShortcutDown || getAnchor() == -1) {
*** 453,480 ****
}
private void focusPageUp() {
int newFocusIndex = onScrollPageUp.call(true);
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
fm.focus(newFocusIndex);
}
private void focusPageDown() {
int newFocusIndex = onScrollPageDown.call(true);
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
fm.focus(newFocusIndex);
}
private void alsoSelectPreviousRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
if (isShiftDown && getAnchor() != -1) {
int newRow = fm.getFocusedIndex() - 1;
if (newRow < 0) return;
--- 440,467 ----
}
private void focusPageUp() {
int newFocusIndex = onScrollPageUp.call(true);
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
fm.focus(newFocusIndex);
}
private void focusPageDown() {
int newFocusIndex = onScrollPageDown.call(true);
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
fm.focus(newFocusIndex);
}
private void alsoSelectPreviousRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
if (isShiftDown && getAnchor() != -1) {
int newRow = fm.getFocusedIndex() - 1;
if (newRow < 0) return;
*** 500,513 ****
onSelectPreviousRow.run();
}
private void alsoSelectNextRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
if (isShiftDown && getAnchor() != -1) {
int newRow = fm.getFocusedIndex() + 1;
int anchor = getAnchor();
--- 487,500 ----
onSelectPreviousRow.run();
}
private void alsoSelectNextRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
if (isShiftDown && getAnchor() != -1) {
int newRow = fm.getFocusedIndex() + 1;
int anchor = getAnchor();
*** 531,541 ****
onSelectNextRow.run();
}
private void clearSelectionOutsideRange(int start, int end) {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
int min = Math.min(start, end);
int max = Math.max(start, end);
--- 518,528 ----
onSelectNextRow.run();
}
private void clearSelectionOutsideRange(int start, int end) {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
int min = Math.min(start, end);
int max = Math.max(start, end);
*** 550,574 ****
}
selectionChanging = false;
}
private void selectPreviousRow() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
if (focusIndex <= 0) {
return;
}
setAnchor(focusIndex - 1);
! getControl().getSelectionModel().clearAndSelect(focusIndex - 1);
onSelectPreviousRow.run();
}
private void selectNextRow() {
! ListView<T> listView = getControl();
FocusModel<T> fm = listView.getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
if (focusIndex == getRowCount() - 1) {
--- 537,561 ----
}
selectionChanging = false;
}
private void selectPreviousRow() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
if (focusIndex <= 0) {
return;
}
setAnchor(focusIndex - 1);
! getNode().getSelectionModel().clearAndSelect(focusIndex - 1);
onSelectPreviousRow.run();
}
private void selectNextRow() {
! ListView<T> listView = getNode();
FocusModel<T> fm = listView.getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
if (focusIndex == getRowCount() - 1) {
*** 583,604 ****
if (onSelectNextRow != null) onSelectNextRow.run();
}
private void selectFirstRow() {
if (getRowCount() > 0) {
! getControl().getSelectionModel().clearAndSelect(0);
if (onMoveToFirstCell != null) onMoveToFirstCell.run();
}
}
private void selectLastRow() {
! getControl().getSelectionModel().clearAndSelect(getRowCount() - 1);
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
private void selectAllPageUp() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
leadIndex = getAnchor() == -1 ? leadIndex : getAnchor();
--- 570,591 ----
if (onSelectNextRow != null) onSelectNextRow.run();
}
private void selectFirstRow() {
if (getRowCount() > 0) {
! getNode().getSelectionModel().clearAndSelect(0);
if (onMoveToFirstCell != null) onMoveToFirstCell.run();
}
}
private void selectLastRow() {
! getNode().getSelectionModel().clearAndSelect(getRowCount() - 1);
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
private void selectAllPageUp() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
leadIndex = getAnchor() == -1 ? leadIndex : getAnchor();
*** 608,618 ****
int leadSelectedIndex = onScrollPageUp.call(false);
// fix for RT-34407
int adjust = leadIndex < leadSelectedIndex ? 1 : -1;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
selectionChanging = true;
if (sm.getSelectionMode() == SelectionMode.SINGLE) {
sm.select(leadSelectedIndex);
--- 595,605 ----
int leadSelectedIndex = onScrollPageUp.call(false);
// fix for RT-34407
int adjust = leadIndex < leadSelectedIndex ? 1 : -1;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
selectionChanging = true;
if (sm.getSelectionMode() == SelectionMode.SINGLE) {
sm.select(leadSelectedIndex);
*** 622,632 ****
}
selectionChanging = false;
}
private void selectAllPageDown() {
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
leadIndex = getAnchor() == -1 ? leadIndex : getAnchor();
--- 609,619 ----
}
selectionChanging = false;
}
private void selectAllPageDown() {
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
leadIndex = getAnchor() == -1 ? leadIndex : getAnchor();
*** 636,646 ****
int leadSelectedIndex = onScrollPageDown.call(false);
// fix for RT-34407
int adjust = leadIndex < leadSelectedIndex ? 1 : -1;
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
selectionChanging = true;
if (sm.getSelectionMode() == SelectionMode.SINGLE) {
sm.select(leadSelectedIndex);
--- 623,633 ----
int leadSelectedIndex = onScrollPageDown.call(false);
// fix for RT-34407
int adjust = leadIndex < leadSelectedIndex ? 1 : -1;
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
selectionChanging = true;
if (sm.getSelectionMode() == SelectionMode.SINGLE) {
sm.select(leadSelectedIndex);
*** 650,663 ****
}
selectionChanging = false;
}
private void selectAllToFirstRow() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
--- 637,650 ----
}
selectionChanging = false;
}
private void selectAllToFirstRow() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
*** 676,693 ****
if (onMoveToFirstCell != null) onMoveToFirstCell.run();
}
private void selectAllToLastRow() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int leadIndex = fm.getFocusedIndex();
if (isShiftDown) {
leadIndex = hasAnchor() ? getAnchor() : leadIndex;
}
sm.clearSelection();
--- 663,681 ----
if (onMoveToFirstCell != null) onMoveToFirstCell.run();
}
private void selectAllToLastRow() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
! 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,716 ****
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
private void selectAll() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
sm.selectAll();
}
private void selectAllToFocus(boolean setAnchorToFocusIndex) {
// Fix for RT-31241
! final ListView<T> listView = getControl();
if (listView.getEditingIndex() >= 0) return;
MultipleSelectionModel<T> sm = listView.getSelectionModel();
if (sm == null) return;
--- 687,704 ----
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
private void selectAll() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
sm.selectAll();
}
private void selectAllToFocus(boolean setAnchorToFocusIndex) {
// Fix for RT-31241
! final ListView<T> listView = getNode();
if (listView.getEditingIndex() >= 0) return;
MultipleSelectionModel<T> sm = listView.getSelectionModel();
if (sm == null) return;
*** 726,754 ****
sm.selectRange(startPos, endPos);
setAnchor(setAnchorToFocusIndex ? focusIndex : anchor);
}
private void cancelEdit() {
! getControl().edit(-1);
}
private void activate() {
! int focusedIndex = getControl().getFocusModel().getFocusedIndex();
! getControl().getSelectionModel().select(focusedIndex);
setAnchor(focusedIndex);
// edit this row also
if (focusedIndex >= 0) {
! getControl().edit(focusedIndex);
}
}
private void toggleFocusOwnerSelection() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int focusedIndex = fm.getFocusedIndex();
if (sm.isSelected(focusedIndex)) {
--- 714,742 ----
sm.selectRange(startPos, endPos);
setAnchor(setAnchorToFocusIndex ? focusIndex : anchor);
}
private void cancelEdit() {
! getNode().edit(-1);
}
private void activate() {
! int focusedIndex = getNode().getFocusModel().getFocusedIndex();
! getNode().getSelectionModel().select(focusedIndex);
setAnchor(focusedIndex);
// edit this row also
if (focusedIndex >= 0) {
! getNode().edit(focusedIndex);
}
}
private void toggleFocusOwnerSelection() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int focusedIndex = fm.getFocusedIndex();
if (sm.isSelected(focusedIndex)) {
*** 764,782 ****
/**************************************************************************
* Discontinuous Selection *
*************************************************************************/
private void discontinuousSelectPreviousRow() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
if (sm.getSelectionMode() != SelectionMode.MULTIPLE) {
selectPreviousRow();
return;
}
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
final int newFocusIndex = focusIndex - 1;
if (newFocusIndex < 0) return;
--- 752,770 ----
/**************************************************************************
* Discontinuous Selection *
*************************************************************************/
private void discontinuousSelectPreviousRow() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
if (sm.getSelectionMode() != SelectionMode.MULTIPLE) {
selectPreviousRow();
return;
}
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
final int newFocusIndex = focusIndex - 1;
if (newFocusIndex < 0) return;
*** 791,809 ****
if (onFocusPreviousRow != null) onFocusPreviousRow.run();
}
private void discontinuousSelectNextRow() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
if (sm.getSelectionMode() != SelectionMode.MULTIPLE) {
selectNextRow();
return;
}
! FocusModel<T> fm = getControl().getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
final int newFocusIndex = focusIndex + 1;
if (newFocusIndex >= getRowCount()) return;
--- 779,797 ----
if (onFocusPreviousRow != null) onFocusPreviousRow.run();
}
private void discontinuousSelectNextRow() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
if (sm.getSelectionMode() != SelectionMode.MULTIPLE) {
selectNextRow();
return;
}
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int focusIndex = fm.getFocusedIndex();
final int newFocusIndex = focusIndex + 1;
if (newFocusIndex >= getRowCount()) return;
*** 818,888 ****
if (onFocusNextRow != null) onFocusNextRow.run();
}
private void discontinuousSelectPageUp() {
! MultipleSelectionModel<T> sm = getControl().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getControl().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();
if (sm == null) return;
! FocusModel<T> fm = getControl().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();
if (sm == null) return;
! FocusModel<T> fm = getControl().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();
if (sm == null) return;
! FocusModel<T> fm = getControl().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;
- }
- }
-
}
--- 806,860 ----
if (onFocusNextRow != null) onFocusNextRow.run();
}
private void discontinuousSelectPageUp() {
! MultipleSelectionModel<T> sm = getNode().getSelectionModel();
if (sm == null) return;
! 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 = getNode().getSelectionModel();
if (sm == null) return;
! 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 = getNode().getSelectionModel();
if (sm == null) return;
! 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 = getNode().getSelectionModel();
if (sm == null) return;
! FocusModel<T> fm = getNode().getFocusModel();
if (fm == null) return;
int index = fm.getFocusedIndex() + 1;
sm.selectRange(index, getRowCount());
if (onMoveToLastCell != null) onMoveToLastCell.run();
}
}