changeset 6483:f06a098b55c4

RT-35949: TreeView: ContextMenu does not selects the TreeCell on which the menu has been started
author jgiles
date Mon, 17 Mar 2014 13:44:38 +1300
parents d2b135379e8d
children 748893eeb873
files modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ListCellBehavior.java 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/TreeCellBehavior.java modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java
diffstat 6 files changed, 135 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Mon Mar 17 11:37:30 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Mon Mar 17 13:44:38 2014 +1300
@@ -31,6 +31,7 @@
 import javafx.scene.control.ListView;
 import javafx.scene.control.MultipleSelectionModel;
 import javafx.scene.control.SelectionMode;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 import sun.util.logging.PlatformLogger;
@@ -109,31 +110,35 @@
      *                                                                         *
      **************************************************************************/
 
-    @Override public void mousePressed(MouseEvent event) {
-        boolean selectedBefore = getControl().isSelected();
-
-        if (event.isSynthesized()) {
+    @Override public void mousePressed(MouseEvent e) {
+        if (e.isSynthesized()) {
             latePress = true;
             return;
         } else {
             latePress  = getControl().isSelected();
             if (!latePress) {
-                doSelect(event);
+                doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                         e.isShiftDown(), e.isShortcutDown());
             }
         }
     }
 
-    @Override public void mouseReleased(MouseEvent event) {
+    @Override public void mouseReleased(MouseEvent e) {
         if (latePress) {
             latePress = false;
-            doSelect(event);
+            doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                     e.isShiftDown(), e.isShortcutDown());
         }
     }
 
-    @Override public void mouseDragged(MouseEvent event) {
+    @Override public void mouseDragged(MouseEvent e) {
         latePress = false;
     }
 
+    @Override public void contextMenuRequested(ContextMenuEvent e) {
+        doSelect(e.getX(), e.getY(), MouseButton.SECONDARY, 1, false, false);
+    }
+
 
 
     /***************************************************************************
@@ -142,7 +147,9 @@
      *                                                                         *
      **************************************************************************/
 
-    private void doSelect(MouseEvent e) {
+    private void doSelect(final double x, final double y, final MouseButton button,
+                          final int clickCount, final boolean shiftDown,
+                          final boolean shortcutDown) {
         // Note that list.select will reset selection
         // for out of bounds indexes. So, need to check
         ListCell<T> listCell = getControl();
@@ -151,13 +158,7 @@
 
         // If the mouse event is not contained within this ListCell, then
         // we don't want to react to it.
-        if (listCell.isEmpty() || ! listCell.contains(e.getX(), e.getY())) {
-            final PlatformLogger logger = Logging.getControlsLogger();
-            if (listCell.isEmpty() && logger.isLoggable(Level.WARNING)) {
-//                logger.warning("ListCell is empty, so mouse pressed event is "
-//                        + "ignored. If you've created a custom cell and overridden "
-//                        + "updateItem, be sure to call super.updateItem(item, empty)");
-            }
+        if (listCell.isEmpty() || ! listCell.contains(x, y)) {
             return;
         }
 
@@ -177,7 +178,7 @@
         // recorded, we record the focus index now so that subsequent shift+clicks
         // result in the correct selection occuring (whilst the focus index moves
         // about).
-        if (e.isShiftDown()) {
+        if (shiftDown) {
             if (! hasAnchor(listView)) {
                 setAnchor(listView, fm.getFocusedIndex());
             }
@@ -185,12 +186,11 @@
             removeAnchor(listView);
         }
 
-        MouseButton button = e.getButton();
         if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) {
             if (sm.getSelectionMode() == SelectionMode.SINGLE) {
-                simpleSelect(e);
+                simpleSelect(button, clickCount, shortcutDown);
             } else {
-                if (e.isControlDown() || e.isMetaDown()) {
+                if (shortcutDown) {
                     if (selected) {
                         // we remove this row from the current selection
                         sm.clearSelection(index);
@@ -199,7 +199,7 @@
                         // We add this row to the current selection
                         sm.select(index);
                     }
-                } else if (e.isShiftDown()) {
+                } else if (shiftDown) {
                     // we add all rows between the current focus and
                     // this row (inclusive) to the current selection.
                     final int focusIndex = getAnchor(listView);
@@ -236,19 +236,19 @@
                     // return selection back to the focus owner
                     fm.focus(index);
                 } else {
-                    simpleSelect(e);
+                    simpleSelect(button, clickCount, shortcutDown);
                 }
             }
         }
     }
 
-    private void simpleSelect(MouseEvent e) {
+    private void simpleSelect(MouseButton button, int clickCount, boolean shortcutDown) {
         ListView<T> lv = getControl().getListView();
         int index = getControl().getIndex();
         MultipleSelectionModel<T> sm = lv.getSelectionModel();
         boolean isAlreadySelected = sm.isSelected(index);
 
-        if (isAlreadySelected && (e.isControlDown() || e.isMetaDown())) {
+        if (isAlreadySelected && shortcutDown) {
             sm.clearSelection(index);
             lv.getFocusModel().focus(index);
             isAlreadySelected = false;
@@ -257,13 +257,13 @@
         }
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.getButton() == MouseButton.PRIMARY) {
-            if (e.getClickCount() == 1 && isAlreadySelected) {
+        if (button == MouseButton.PRIMARY) {
+            if (clickCount == 1 && isAlreadySelected) {
                 lv.edit(index);
-            } else if (e.getClickCount() == 1) {
+            } else if (clickCount == 1) {
                 // cancel editing
                 lv.edit(-1);
-            } else if (e.getClickCount() == 2 && getControl().isEditable()) {
+            } else if (clickCount == 2 && getControl().isEditable()) {
                 lv.edit(index);
             }
         }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java	Mon Mar 17 11:37:30 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java	Mon Mar 17 13:44:38 2014 +1300
@@ -32,6 +32,7 @@
 import javafx.scene.control.TableFocusModel;
 import javafx.scene.control.TablePositionBase;
 import javafx.scene.control.TableSelectionModel;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 
@@ -130,28 +131,34 @@
      *                                                                         *
      **************************************************************************/    
     
-    @Override public void mousePressed(MouseEvent event) {
-        if (event.isSynthesized()) {
+    @Override public void mousePressed(MouseEvent e) {
+        if (e.isSynthesized()) {
             latePress = true;
         } else {
             latePress  = getControl().isSelected();
             if (!latePress) {
-                doSelect(event);
+                doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                         e.isShiftDown(), e.isShortcutDown());
             }
         }
     }
     
-    @Override public void mouseReleased(MouseEvent event) {
+    @Override public void mouseReleased(MouseEvent e) {
         if (latePress) {
             latePress = false;
-            doSelect(event);
+            doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                     e.isShiftDown(), e.isShortcutDown());
         }
     }
     
-    @Override public void mouseDragged(MouseEvent event) {
+    @Override public void mouseDragged(MouseEvent e) {
         latePress = false;
     }
-    
+
+    @Override public void contextMenuRequested(ContextMenuEvent e) {
+        doSelect(e.getX(), e.getY(), MouseButton.SECONDARY, 1, false, false);
+    }
+
     
     
     /***************************************************************************
@@ -160,14 +167,15 @@
      *                                                                         *
      **************************************************************************/   
     
-    private void doSelect(MouseEvent e) {
+    private void doSelect(final double x, final double y, final MouseButton button,
+                          final int clickCount, final boolean shiftDown, final boolean shortcutDown) {
         // Note that table.select will reset selection
         // for out of bounds indexes. So, need to check
         final C tableCell = getControl();
 
         // If the mouse event is not contained within this tableCell, then
         // we don't want to react to it.
-        if (! tableCell.contains(e.getX(), e.getY())) return;
+        if (! tableCell.contains(x, y)) return;
 
         final Control tableView = getTableControl();
         if (tableView == null) return;
@@ -190,7 +198,7 @@
 
         // if the user has clicked on the disclosure node, we do nothing other
         // than expand/collapse the tree item (if applicable). We do not do editing!
-        boolean disclosureClicked = checkDisclosureNodeClick(e);
+        boolean disclosureClicked = checkDisclosureNodeClick(x, y);
         if (disclosureClicked) {
             return;
         }
@@ -199,7 +207,7 @@
         // recorded, we record the focus index now so that subsequent shift+clicks
         // result in the correct selection occuring (whilst the focus index moves
         // about).
-        if (e.isShiftDown()) {
+        if (shiftDown) {
             if (! hasAnchor(tableView)) {
                 setAnchor(tableView, focusedCell);
             }
@@ -209,12 +217,11 @@
 
         // we must update the table appropriately, and this is determined by
         // what modifiers the user held down as they released the mouse.
-        MouseButton button = e.getButton();
-        if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) { 
+        if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) {
             if (sm.getSelectionMode() == SelectionMode.SINGLE) {
-                simpleSelect(e);
+                simpleSelect(button, clickCount, shortcutDown);
             } else {
-                if (e.isControlDown() || e.isMetaDown()) {
+                if (shortcutDown) {
                     if (selected) {
                         // we remove this row/cell from the current selection
                         sm.clearSelection(row, tableColumn);
@@ -223,7 +230,7 @@
                         // We add this cell/row to the current selection
                         sm.select(row, tableColumn);
                     }
-                } else if (e.isShiftDown()) {
+                } else if (shiftDown) {
                     // we add all cells/rows between the current selection focus and
                     // this cell/row (inclusive) to the current selection.
                     final TablePositionBase anchor = getAnchor(tableView, focusedCell);
@@ -283,19 +290,19 @@
                     // return selection back to the focus owner
                     // focus(anchor.getRow(), tableColumn);
                 } else {
-                    simpleSelect(e);
+                    simpleSelect(button, clickCount, shortcutDown);
                 }
             }
         }
     }
 
-    protected void simpleSelect(MouseEvent e) {
+    protected void simpleSelect(MouseButton button, int clickCount, boolean shortcutDown) {
         final TableSelectionModel<S> sm = getSelectionModel();
         final int row = getControl().getIndex();
         final TableColumnBase<S,T> column = getTableColumn();
         boolean isAlreadySelected = sm.isSelected(row, sm.isCellSelectionEnabled() ? column : null);
 
-        if (isAlreadySelected && (e.isControlDown() || e.isMetaDown())) {
+        if (isAlreadySelected && shortcutDown) {
             sm.clearSelection(row, column);
             getFocusModel().focus(row, (TC) (sm.isCellSelectionEnabled() ? column : null));
             isAlreadySelected = false;
@@ -305,20 +312,20 @@
         }
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.getButton() == MouseButton.PRIMARY) {
-            if (e.getClickCount() == 1 && isAlreadySelected) {
+        if (button == MouseButton.PRIMARY) {
+            if (clickCount == 1 && isAlreadySelected) {
                 edit(row, column);
-            } else if (e.getClickCount() == 1) {
+            } else if (clickCount == 1) {
                 // cancel editing
                 edit(-1, null);
-            } else if (e.getClickCount() == 2 && getControl().isEditable()) {
+            } else if (clickCount == 2 && getControl().isEditable()) {
                 // edit at the specified row and column
                 edit(row, column);
             }
         }
     }
 
-    protected boolean checkDisclosureNodeClick(MouseEvent e) {
+    protected boolean checkDisclosureNodeClick(double x, double y) {
         // by default we don't care about disclosure nodes
         return false;
     }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java	Mon Mar 17 11:37:30 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java	Mon Mar 17 13:44:38 2014 +1300
@@ -26,6 +26,7 @@
 package com.sun.javafx.scene.control.behavior;
 
 import javafx.scene.control.*;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 
@@ -66,31 +67,36 @@
      *                                                                         *
      **************************************************************************/
 
-    @Override public void mousePressed(MouseEvent event) {
+    @Override public void mousePressed(MouseEvent e) {
         // we only care about clicks to the right of the right-most column
-        if (! isClickOutsideCellBounds(event.getX())) return;
+        if (! isClickOutsideCellBounds(e.getX())) return;
 
-        if (event.isSynthesized()) {
+        if (e.isSynthesized()) {
             latePress = true;
         } else {
             latePress  = getControl().isSelected();
             if (!latePress) {
-                doSelect(event);
+                doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                         e.isShiftDown(), e.isShortcutDown());
             }
         }
     }
 
-    @Override public void mouseReleased(MouseEvent event) {
+    @Override public void mouseReleased(MouseEvent e) {
         if (latePress) {
             latePress = false;
-            doSelect(event);
+            doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                     e.isShiftDown(), e.isShortcutDown());
         }
     }
 
-    @Override public void mouseDragged(MouseEvent event) {
+    @Override public void mouseDragged(MouseEvent e) {
         latePress = false;
     }
 
+    @Override public void contextMenuRequested(ContextMenuEvent e) {
+        doSelect(e.getX(), e.getY(), MouseButton.SECONDARY, 1, false, false);
+    }
 
 
 
@@ -100,11 +106,9 @@
      *                                                                         *
      **************************************************************************/
 
-    private void doSelect(MouseEvent e) {
-        super.mouseReleased(e);
-        
-        if (e.getButton() != MouseButton.PRIMARY) return;
-        
+    private void doSelect(final double x, final double y, final MouseButton button,
+                          final int clickCount, final boolean shiftDown,
+                          final boolean shortcutDown) {
         final TableRow<T> tableRow = getControl();
         final TableView<T> table = tableRow.getTableView();
         if (table == null) return;
@@ -113,20 +117,19 @@
         
         final int index = getControl().getIndex();
         final boolean isAlreadySelected = sm.isSelected(index);
-        int clickCount = e.getClickCount();
         if (clickCount == 1) {
             // we only care about clicks to the right of the right-most column
-            if (! isClickOutsideCellBounds(e.getX())) return;
+            if (! isClickOutsideCellBounds(x)) return;
             
             // In the case of clicking to the right of the rightmost
             // TreeTableCell, we should still support selection, so that
             // is what we are doing here.
-            if (isAlreadySelected && e.isShortcutDown()) {
+            if (isAlreadySelected && shortcutDown) {
                 sm.clearSelection(index);
             } else {
-                if (e.isShortcutDown()) {
+                if (shortcutDown) {
                     sm.select(tableRow.getIndex());
-                } else if (e.isShiftDown()) {
+                } else if (shiftDown) {
                     // we add all rows between the current focus and
                     // this row (inclusive) to the current selection.
                     TablePositionBase anchor = TableCellBehavior.getAnchor(table, table.getFocusModel().getFocusedCell());
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Mon Mar 17 11:37:30 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Mon Mar 17 13:44:38 2014 +1300
@@ -33,6 +33,7 @@
 import javafx.scene.control.TreeCell;
 import javafx.scene.control.TreeItem;
 import javafx.scene.control.TreeView;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 import sun.util.logging.PlatformLogger;
@@ -112,30 +113,34 @@
      *                                                                         *
      **************************************************************************/
 
-    @Override public void mousePressed(MouseEvent event) {
+    @Override public void mousePressed(MouseEvent e) {
 
-        if (event.isSynthesized()) {
+        if (e.isSynthesized()) {
             latePress = true;
         } else {
             latePress  = getControl().isSelected();
             if (!latePress) {
-                doSelect(event);
+                doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                         e.isShiftDown(), e.isShortcutDown());
             }
         }
     }
 
-    @Override public void mouseReleased(MouseEvent event) {
+    @Override public void mouseReleased(MouseEvent e) {
         if (latePress) {
             latePress = false;
-            doSelect(event);
+            doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                     e.isShiftDown(), e.isShortcutDown());
         }
     }
 
-    @Override public void mouseDragged(MouseEvent event) {
+    @Override public void mouseDragged(MouseEvent e) {
         latePress = false;
     }
 
-
+    @Override public void contextMenuRequested(ContextMenuEvent e) {
+        doSelect(e.getX(), e.getY(), MouseButton.SECONDARY, 1, false, false);
+    }
 
     /***************************************************************************
      *                                                                         *
@@ -143,7 +148,8 @@
      *                                                                         *
      **************************************************************************/
 
-    private void doSelect(MouseEvent event) {
+    private void doSelect(final double x, final double y, final MouseButton button,
+                          final int clickCount, final boolean shiftDown, final boolean shortcutDown) {
         // we update the cell to point to the new tree node
         TreeCell<T> treeCell = getControl();
         TreeView<T> treeView = treeCell.getTreeView();
@@ -151,13 +157,7 @@
 
         // If the mouse event is not contained within this TreeCell, then
         // we don't want to react to it.
-        if (treeCell.isEmpty() || ! treeCell.contains(event.getX(), event.getY())) {
-            final PlatformLogger logger = Logging.getControlsLogger();
-            if (treeCell.isEmpty() && logger.isLoggable(Level.WARNING)) {
-//                logger.warning("TreeCell is empty, so mouse pressed event is "
-//                        + "ignored. If you've created a custom cell and overridden "
-//                        + "updateItem, be sure to call super.updateItem(item, empty)");
-            }
+        if (treeCell.isEmpty() || ! treeCell.contains(x, y)) {
             return;
         }
 
@@ -173,7 +173,7 @@
         // than expand/collapse the tree item (if applicable). We do not do editing!
         Node disclosureNode = treeCell.getDisclosureNode();
         if (disclosureNode != null) {
-            if (disclosureNode.getBoundsInParent().contains(event.getX(), event.getY())) {
+            if (disclosureNode.getBoundsInParent().contains(x, y)) {
                 if (treeCell.getTreeItem() != null) {
                     treeCell.getTreeItem().setExpanded(! treeCell.getTreeItem().isExpanded());
                 }
@@ -185,7 +185,7 @@
         // recorded, we record the focus index now so that subsequent shift+clicks
         // result in the correct selection occuring (whilst the focus index moves
         // about).
-        if (event.isShiftDown()) {
+        if (shiftDown) {
             if (! hasAnchor(treeView)) {
                 setAnchor(treeView, fm.getFocusedIndex());
             }
@@ -193,12 +193,11 @@
             removeAnchor(treeView);
         }
 
-        MouseButton button = event.getButton();
         if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) {
             if (sm.getSelectionMode() == SelectionMode.SINGLE) {
-                simpleSelect(event);
+                simpleSelect(button, clickCount, shortcutDown);
             } else {
-                if (event.isControlDown() || event.isMetaDown()) {
+                if (shortcutDown) {
                     if (selected) {
                         // we remove this row from the current selection
                         sm.clearSelection(index);
@@ -207,7 +206,7 @@
                         // We add this row to the current selection
                         sm.select(index);
                     }
-                } else if (event.isShiftDown() && event.getClickCount() == 1) {
+                } else if (shiftDown && clickCount == 1) {
                     // we add all rows between the current selection focus and
                     // this row (inclusive) to the current selection.
                     final int focusedIndex = getAnchor(treeView);
@@ -243,20 +242,20 @@
 
                     fm.focus(index);
                 } else {
-                    simpleSelect(event);
+                    simpleSelect(button, clickCount, shortcutDown);
                 }
             }
         }
     }
 
-    private void simpleSelect(MouseEvent e) {
+    private void simpleSelect(MouseButton button, int clickCount, boolean shortcutDown) {
         TreeView<T> tv = getControl().getTreeView();
         TreeItem<T> treeItem = getControl().getTreeItem();
         int index = getControl().getIndex();
         MultipleSelectionModel<TreeItem<T>> sm = tv.getSelectionModel();
         boolean isAlreadySelected = sm.isSelected(index);
 
-        if (isAlreadySelected && (e.isControlDown() || e.isMetaDown())) {
+        if (isAlreadySelected && shortcutDown) {
             sm.clearSelection(index);
             tv.getFocusModel().focus(index);
             isAlreadySelected = false;
@@ -265,16 +264,16 @@
         }
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.getButton() == MouseButton.PRIMARY) {
-            if (e.getClickCount() == 1 && isAlreadySelected) {
+        if (button == MouseButton.PRIMARY) {
+            if (clickCount == 1 && isAlreadySelected) {
                 tv.edit(treeItem);
-            } else if (e.getClickCount() == 1) {
+            } else if (clickCount == 1) {
                 // cancel editing
                 tv.edit(null);
-            } else if (e.getClickCount() == 2 && treeItem.isLeaf()) {
+            } else if (clickCount == 2 && treeItem.isLeaf()) {
                 // attempt to edit
                 tv.edit(treeItem);
-            } else if (e.getClickCount() % 2 == 0) {
+            } else if (clickCount % 2 == 0) {
                 // try to expand/collapse branch tree item
                 treeItem.setExpanded(! treeItem.isExpanded());
             }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java	Mon Mar 17 11:37:30 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableCellBehavior.java	Mon Mar 17 13:44:38 2014 +1300
@@ -113,11 +113,11 @@
         getTableControl().edit(row, (TreeTableColumn)tc);
     }
 
-    @Override protected boolean checkDisclosureNodeClick(MouseEvent e) {
+    @Override protected boolean checkDisclosureNodeClick(double x, double y) {
         final TreeItem<S> treeItem = getControl().getTreeTableRow().getTreeItem();
         final Node disclosureNode = getControl().getTreeTableRow().getDisclosureNode();
         if (disclosureNode != null) {
-            if (disclosureNode.getBoundsInParent().contains(e.getX(), e.getY())) {
+            if (disclosureNode.getBoundsInParent().contains(x, y)) {
                 if (treeItem != null) {
                     treeItem.setExpanded(! treeItem.isExpanded());
                 }
@@ -127,7 +127,7 @@
         return false;
     }
     
-    @Override protected void simpleSelect(MouseEvent e) {
+    @Override protected void simpleSelect(MouseButton button, int clickCount, boolean shortcutDown) {
         TreeTableView<S> tv = getControl().getTreeTableView();
         TreeItem treeItem = getControl().getTreeTableRow().getTreeItem();
         int index = getControl().getIndex();
@@ -136,7 +136,7 @@
         
         boolean isAlreadySelected = sm.isSelected(index, column);
 
-        if (isAlreadySelected && (e.isControlDown() || e.isMetaDown())) {
+        if (isAlreadySelected && shortcutDown) {
             sm.clearSelection(index, column);
             isAlreadySelected = false;
         } else {
@@ -145,16 +145,16 @@
         }
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.getButton() == MouseButton.PRIMARY) {
-            if (e.getClickCount() == 1 && isAlreadySelected) {
+        if (button == MouseButton.PRIMARY) {
+            if (clickCount == 1 && isAlreadySelected) {
                 tv.edit(index, column);
-            } else if (e.getClickCount() == 1) {
+            } else if (clickCount == 1) {
                 // cancel editing
                 tv.edit(-1, null);
-            } else if (e.getClickCount() == 2 && treeItem.isLeaf()) {
+            } else if (clickCount == 2 && treeItem.isLeaf()) {
                 // attempt to edit
                 tv.edit(index, column);
-            } else if (e.getClickCount() % 2 == 0) {
+            } else if (clickCount % 2 == 0) {
                 // try to expand/collapse branch tree item
                 treeItem.setExpanded(! treeItem.isExpanded());
             }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java	Mon Mar 17 11:37:30 2014 +1300
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java	Mon Mar 17 13:44:38 2014 +1300
@@ -28,6 +28,7 @@
 import javafx.scene.Node;
 import javafx.scene.control.*;
 import javafx.scene.control.TreeTableView.TreeTableViewSelectionModel;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 
@@ -66,24 +67,26 @@
      *                                                                         *
      **************************************************************************/
 
-    @Override public void mousePressed(MouseEvent event) {
+    @Override public void mousePressed(MouseEvent e) {
         // we only care about clicks to the right of the right-most column
-        if (! isClickOutsideCellBounds(event.getX())) return;
+        if (! isClickOutsideCellBounds(e.getX())) return;
 
-        if (event.isSynthesized()) {
+        if (e.isSynthesized()) {
             latePress = true;
         } else {
             latePress  = getControl().isSelected();
             if (!latePress) {
-                doSelect(event);
+                doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                         e.isShiftDown(), e.isShortcutDown());
             }
         }
     }
 
-    @Override public void mouseReleased(MouseEvent event) {
+    @Override public void mouseReleased(MouseEvent e) {
         if (latePress) {
             latePress = false;
-            doSelect(event);
+            doSelect(e.getX(), e.getY(), e.getButton(), e.getClickCount(),
+                     e.isShiftDown(), e.isShortcutDown());
         }
     }
 
@@ -91,6 +94,9 @@
         latePress = false;
     }
 
+    @Override public void contextMenuRequested(ContextMenuEvent e) {
+        doSelect(e.getX(), e.getY(), MouseButton.SECONDARY, 1, false, false);
+    }
 
 
 
@@ -100,11 +106,8 @@
      *                                                                         *
      **************************************************************************/
 
-    private void doSelect(MouseEvent e) {
-        super.mouseReleased(e);
-        
-        if (e.getButton() != MouseButton.PRIMARY) return;
-        
+    private void doSelect(final double x, final double y, final MouseButton button,
+                          final int clickCount, final boolean shiftDown, final boolean shortcutDown) {
         TreeTableRow<T> treeTableRow = getControl();
         TreeItem<T> treeItem = treeTableRow.getTreeItem();
         if (treeItem == null) return;
@@ -113,7 +116,7 @@
         // than expand/collapse the tree item (if applicable). We do not do editing!
         Node disclosureNode = treeTableRow.getDisclosureNode();
         if (disclosureNode != null) {
-            if (disclosureNode.getBoundsInParent().contains(e.getX(), e.getY())) {
+            if (disclosureNode.getBoundsInParent().contains(x, y)) {
                 treeItem.setExpanded(! treeItem.isExpanded());
                 return;
             }
@@ -126,7 +129,6 @@
         
         final int index = getControl().getIndex();
         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)
@@ -136,17 +138,17 @@
                 width += columns.get(i).getWidth();
             }
             
-            if (e.getX() < width) return;
+            if (x < width) return;
             
             // In the case of clicking to the right of the rightmost
             // TreeTableCell, we should still support selection, so that
             // is what we are doing here.
-            if (isAlreadySelected && e.isShortcutDown()) {
+            if (isAlreadySelected && shortcutDown) {
                 sm.clearSelection(index);
             } else {
-                if (e.isShortcutDown()) {
+                if (shortcutDown) {
                     sm.select(treeTableRow.getIndex());
-                } else if (e.isShiftDown()) {
+                } else if (shiftDown) {
                     // we add all rows between the current focus and
                     // this row (inclusive) to the current selection.
                     TablePositionBase anchor = TreeTableCellBehavior.getAnchor(table, table.getFocusModel().getFocusedCell());