changeset 4858:2e11c8f35ee5

RT-31104: TableView makes multiple selection drags difficult
author jgiles
date Mon, 02 Sep 2013 13:16:53 +1200
parents 3acaf13c190c
children bd2c6e6b661a
files modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java
diffstat 3 files changed, 226 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java	Mon Sep 02 12:54:39 2013 +1200
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java	Mon Sep 02 13:16:53 2013 +1200
@@ -25,13 +25,7 @@
 
 package com.sun.javafx.scene.control.behavior;
 
-import javafx.scene.control.Control;
-import javafx.scene.control.IndexedCell;
-import javafx.scene.control.SelectionMode;
-import javafx.scene.control.TableColumnBase;
-import javafx.scene.control.TableFocusModel;
-import javafx.scene.control.TablePositionBase;
-import javafx.scene.control.TableSelectionModel;
+import javafx.scene.control.*;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 import java.util.ArrayList;
@@ -139,9 +133,9 @@
      **************************************************************************/    
     
     @Override public void mousePressed(MouseEvent event) {
-        boolean selectedBefore = getControl().isSelected();
+        boolean selectedBefore = isSelected();
         
-        if (getControl().isSelected()) {
+        if (isSelected()) {
             latePress = true;
             return;
         }
@@ -149,7 +143,7 @@
         doSelect(event);
         
         if (IS_TOUCH_SUPPORTED && selectedBefore) {
-            wasSelected = getControl().isSelected();
+            wasSelected = isSelected();
         }
     }
     
@@ -168,7 +162,7 @@
         // the mouse has now been dragged on a touch device, we should
         // remove the selection if we just added it in the last mouse press
         // event
-        if (IS_TOUCH_SUPPORTED && ! wasSelected && getControl().isSelected()) {
+        if (IS_TOUCH_SUPPORTED && ! wasSelected && isSelected()) {
             getSelectionModel().clearSelection(getControl().getIndex());
         }
     }
@@ -199,7 +193,7 @@
         TableSelectionModel<S> sm = getSelectionModel();
         if (sm == null) return;
 
-        final boolean selected = ! sm.isCellSelectionEnabled() ? isTableRowSelected() : tableCell.isSelected();
+        final boolean selected = isSelected();
         final int row = tableCell.getIndex();
         final int column = getColumn();
         final TableColumnBase<S,T> tableColumn = getTableColumn();
@@ -334,4 +328,16 @@
 
         return -1;
     }
+
+    private boolean isSelected() {
+        TableSelectionModel<S> sm = getSelectionModel();
+        if (sm == null) return false;
+
+        if (sm.isCellSelectionEnabled()) {
+            final C cell = getControl();
+            return cell.isSelected();
+        } else {
+            return isTableRowSelected();
+        }
+    }
 }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java	Mon Sep 02 12:54:39 2013 +1200
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java	Mon Sep 02 13:16:53 2013 +1200
@@ -35,11 +35,99 @@
 
 public class TableRowBehavior<T> extends CellBehaviorBase<TableRow<T>> {
 
+    /***************************************************************************
+     *                                                                         *
+     * Private fields                                                          *
+     *                                                                         *
+     **************************************************************************/
+
+    // For RT-17456: have selection occur as fast as possible with mouse input.
+    // The idea is (consistently with some native applications we've tested) to
+    // do the action as soon as you can. It takes a bit more coding but provides
+    // the best feel:
+    //  - when you click on a not-selected item, you can select immediately on press
+    //  - when you click on a selected item, you need to wait whether DragDetected or Release comes first
+    //
+    // To support touch devices, we have to slightly modify this behavior, such
+    // that selection only happens on mouse release, if only minimal dragging
+    // has occurred.
+    private boolean latePress = false;
+    private boolean wasSelected = false;
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Constructors                                                            *
+     *                                                                         *
+     **************************************************************************/
+
     public TableRowBehavior(TableRow<T> control) {
         super(control, Collections.EMPTY_LIST);
     }
 
-    @Override public void mouseReleased(MouseEvent e) {
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Public API                                                              *
+     *                                                                         *
+     **************************************************************************/
+
+    @Override public void mousePressed(MouseEvent event) {
+        // we only care about clicks to the right of the right-most column
+        if (! isClickOutsideCellBounds(event.getX())) return;
+
+        boolean selectedBefore = getControl().isSelected();
+
+        if (getControl().isSelected()) {
+            latePress = true;
+            return;
+        }
+
+        doSelect(event);
+
+        if (IS_TOUCH_SUPPORTED && selectedBefore) {
+            wasSelected = getControl().isSelected();
+        }
+    }
+
+    @Override public void mouseReleased(MouseEvent event) {
+        // we only care about clicks to the right of the right-most column
+        if (! isClickOutsideCellBounds(event.getX())) return;
+
+        if (latePress) {
+            latePress = false;
+            doSelect(event);
+        }
+
+        wasSelected = false;
+    }
+
+    @Override public void mouseDragged(MouseEvent event) {
+        // we only care about clicks to the right of the right-most column
+        if (! isClickOutsideCellBounds(event.getX())) return;
+
+        latePress = false;
+
+        // the mouse has now been dragged on a touch device, we should
+        // remove the selection if we just added it in the last mouse press
+        // event
+        if (IS_TOUCH_SUPPORTED && ! wasSelected && getControl().isSelected()) {
+            getControl().getTableView().getSelectionModel().clearSelection(getControl().getIndex());
+        }
+    }
+
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Private implementation                                                  *
+     *                                                                         *
+     **************************************************************************/
+
+    private void doSelect(MouseEvent e) {
         super.mouseReleased(e);
         
         if (e.getButton() != MouseButton.PRIMARY) return;
@@ -54,15 +142,8 @@
         final boolean isAlreadySelected = sm.isSelected(index);
         int clickCount = e.getClickCount();
         if (clickCount == 1) {
-            // get width of all visible columns (we only care about clicks to the
-            // right of the right-most column)
-            List<TableColumn<T, ?>> columns = table.getVisibleLeafColumns();
-            double width = 0.0;
-            for (int i = 0; i < columns.size(); i++) {
-                width += columns.get(i).getWidth();
-            }
-            
-            if (e.getX() < width) return;
+            // we only care about clicks to the right of the right-most column
+            if (! isClickOutsideCellBounds(e.getX())) return;
             
             // In the case of clicking to the right of the rightmost
             // TreeTableCell, we should still support selection, so that
@@ -109,4 +190,19 @@
             }
         }
     }
+
+    private boolean isClickOutsideCellBounds(final double x) {
+        // get width of all visible columns (we only care about clicks to the
+        // right of the right-most column)
+        final TableRow<T> tableRow = getControl();
+        final TableView<T> table = tableRow.getTableView();
+        if (table == null) return false;
+        List<TableColumn<T, ?>> columns = table.getVisibleLeafColumns();
+        double width = 0.0;
+        for (int i = 0; i < columns.size(); i++) {
+            width += columns.get(i).getWidth();
+        }
+
+        return x > width;
+    }
 }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java	Mon Sep 02 12:54:39 2013 +1200
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java	Mon Sep 02 13:16:53 2013 +1200
@@ -37,11 +37,97 @@
 
 public class TreeTableRowBehavior<T> extends CellBehaviorBase<TreeTableRow<T>> {
 
+    /***************************************************************************
+     *                                                                         *
+     * Private fields                                                          *
+     *                                                                         *
+     **************************************************************************/
+
+    // For RT-17456: have selection occur as fast as possible with mouse input.
+    // The idea is (consistently with some native applications we've tested) to
+    // do the action as soon as you can. It takes a bit more coding but provides
+    // the best feel:
+    //  - when you click on a not-selected item, you can select immediately on press
+    //  - when you click on a selected item, you need to wait whether DragDetected or Release comes first
+    //
+    // To support touch devices, we have to slightly modify this behavior, such
+    // that selection only happens on mouse release, if only minimal dragging
+    // has occurred.
+    private boolean latePress = false;
+    private boolean wasSelected = false;
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Constructors                                                            *
+     *                                                                         *
+     **************************************************************************/
+
     public TreeTableRowBehavior(TreeTableRow<T> control) {
         super(control, Collections.EMPTY_LIST);
     }
 
-    @Override public void mouseReleased(MouseEvent e) {
+    /***************************************************************************
+     *                                                                         *
+     * Public API                                                              *
+     *                                                                         *
+     **************************************************************************/
+
+    @Override public void mousePressed(MouseEvent event) {
+        // we only care about clicks to the right of the right-most column
+        if (! isClickOutsideCellBounds(event.getX())) return;
+
+        boolean selectedBefore = getControl().isSelected();
+
+        if (getControl().isSelected()) {
+            latePress = true;
+            return;
+        }
+
+        doSelect(event);
+
+        if (IS_TOUCH_SUPPORTED && selectedBefore) {
+            wasSelected = getControl().isSelected();
+        }
+    }
+
+    @Override public void mouseReleased(MouseEvent event) {
+        // we only care about clicks to the right of the right-most column
+        if (! isClickOutsideCellBounds(event.getX())) return;
+
+        if (latePress) {
+            latePress = false;
+            doSelect(event);
+        }
+
+        wasSelected = false;
+    }
+
+    @Override public void mouseDragged(MouseEvent event) {
+        // we only care about clicks to the right of the right-most column
+        if (! isClickOutsideCellBounds(event.getX())) return;
+
+        latePress = false;
+
+        // the mouse has now been dragged on a touch device, we should
+        // remove the selection if we just added it in the last mouse press
+        // event
+        if (IS_TOUCH_SUPPORTED && ! wasSelected && getControl().isSelected()) {
+            getControl().getTreeTableView().getSelectionModel().clearSelection(getControl().getIndex());
+        }
+    }
+
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Private implementation                                                  *
+     *                                                                         *
+     **************************************************************************/
+
+    private void doSelect(MouseEvent e) {
         super.mouseReleased(e);
         
         if (e.getButton() != MouseButton.PRIMARY) return;
@@ -124,4 +210,19 @@
             }
         }
     }
+
+    private boolean isClickOutsideCellBounds(final double x) {
+        // get width of all visible columns (we only care about clicks to the
+        // right of the right-most column)
+        final TreeTableRow<T> tableRow = getControl();
+        final TreeTableView<T> table = tableRow.getTreeTableView();
+        if (table == null) return false;
+        List<TreeTableColumn<T, ?>> columns = table.getVisibleLeafColumns();
+        double width = 0.0;
+        for (int i = 0; i < columns.size(); i++) {
+            width += columns.get(i).getWidth();
+        }
+
+        return x > width;
+    }
 }