changeset 103:6cbfd718d28f

RT-15275: Use platforms context menu detect event to show ContextMenu instead of MouseRelease event.
author snorthov
date Thu, 01 Dec 2011 11:33:58 -0500
parents 31fb596f444a
children 3ae65a0b9d75
files javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBehavior.java javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBindings.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/SkinBase.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TabPaneSkin.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableColumnHeader.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableHeaderRow.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java
diffstat 8 files changed, 73 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBehavior.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBehavior.java	Thu Dec 01 11:33:58 2011 -0500
@@ -134,7 +134,6 @@
             else if ("Unselect".equals(name)) textInputControl.deselect();
             else if ("SelectHome".equals(name)) selectHome();
             else if ("SelectEnd".equals(name)) selectEnd();
-            else if ("ShowContextMenu".equals(name)) showContextMenu();
             else super.callAction(name);
             setCaretAnimating(true);
         } else if ("Copy".equals(name)) {
@@ -235,12 +234,6 @@
         }
     }
 
-    public void showContextMenu() {
-        if (getControl().getSkin() instanceof SkinBase) {
-            ((SkinBase)getControl().getSkin()).showContextMenu();
-        }
-    }
-
     private void selectEnd() {
         TextInputControl textInputControl = getControl();
         if (macOS) {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBindings.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBindings.java	Thu Dec 01 11:33:58 2011 -0500
@@ -70,9 +70,6 @@
         BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED,        "SelectEnd").shift());
         BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED,     "SelectEnd").shift());
         BINDINGS.add(new KeyBinding(END, KEY_PRESSED,         "SelectEnd").shift());
-        // context menu
-        BINDINGS.add(new KeyBinding(CONTEXT_MENU, KEY_PRESSED, "ShowContextMenu"));
-        BINDINGS.add(new KeyBinding(F10, KEY_PRESSED,          "ShowContextMenu").shift());
 
         // platform specific settings
         if (PlatformUtil.isMac()) {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/SkinBase.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/SkinBase.java	Thu Dec 01 11:33:58 2011 -0500
@@ -34,7 +34,6 @@
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.beans.value.WeakChangeListener;
-import javafx.collections.ListChangeListener.Change;
 import javafx.event.EventHandler;
 import javafx.event.EventType;
 import javafx.scene.Node;
@@ -42,7 +41,7 @@
 import javafx.scene.control.ContextMenu;
 import javafx.scene.control.Control;
 import javafx.scene.control.Skin;
-import javafx.scene.input.MouseButton;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.StackPane;
 
@@ -136,6 +135,8 @@
         this.removeEventHandler(MouseEvent.MOUSE_PRESSED, mouseHandler);
         this.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseHandler);
         this.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseHandler);
+        
+        control.removeEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, contextMenuHandler);
 
         this.control = null;
         this.behavior = null;
@@ -172,15 +173,9 @@
         this.addEventHandler(MouseEvent.MOUSE_RELEASED, mouseHandler);
         this.addEventHandler(MouseEvent.MOUSE_DRAGGED, mouseHandler);
         
-        // we add a listener for mouse released events to show the context menu
+        // we add a listener for menu request events to show the context menu
         // that may be set on the Control
-        this.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
-            @Override public void handle(MouseEvent event) {
-                if (event.getButton() == MouseButton.SECONDARY) {
-                    showContextMenu(event.getScreenX(), event.getScreenY());
-                }
-            }
-        });
+        control.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, contextMenuHandler);
 
         // Default behavior for controls is to consume all mouse events
         consumeMouseEvents(true);
@@ -190,19 +185,21 @@
         return behavior;
     }
 
+    public ContextMenu getContextMenu() {
+        return getSkinnable().getContextMenu();
+    }
+    
     /**
      * Called for key events with no specific mouse location.
      *
-     * Subclasses override this to decide location and call showContextMenu(x, y).
+     * Subclasses override this to decide location and call show the context menu.
      */
-    public void showContextMenu() {
-    }
-
-    protected void showContextMenu(double x, double y) {
-        ContextMenu menu = getSkinnable().getContextMenu();
+    public boolean showContextMenu(ContextMenu menu, double x, double y, boolean isKeyboardTrigger) {
         if (menu != null) {
             menu.show(control, x, y);
+            return true;
         }
+        return false;
     }
 
 
@@ -333,4 +330,19 @@
             }
         }
     };
+    
+    /**
+     * Handles conext menu requests by popping up the menu.
+     * Note that we use this pattern to remove some of the anonymous inner
+     * classes which we'd otherwise have to create. When lambda expressions
+     * are supported, we could do it that way instead (or use MethodHandles).
+     */
+    private final EventHandler<ContextMenuEvent> contextMenuHandler = new EventHandler<ContextMenuEvent>() {
+        @Override public void handle(ContextMenuEvent event) {
+            // If a context menu was shown, consume the event to prevent multiple context menus
+            if (showContextMenu(getContextMenu (), event.getScreenX(), event.getScreenY(), event.isKeyboardTrigger())) {
+                event.consume();
+            }
+        }
+    };
 }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TabPaneSkin.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TabPaneSkin.java	Thu Dec 01 11:33:58 2011 -0500
@@ -55,6 +55,7 @@
 import javafx.scene.control.Tooltip;
 import javafx.scene.effect.DropShadow;
 import javafx.scene.image.ImageView;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.Pane;
@@ -998,6 +999,14 @@
             getSkinnable().tabMinHeightProperty().addListener(controlListener);
             getSkinnable().tabMaxHeightProperty().addListener(controlListener);
 
+            setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
+                @Override public void handle(ContextMenuEvent me) {
+                   if (getTab().getContextMenu() != null) {
+                        getTab().getContextMenu().show(inner, me.getScreenX(), me.getScreenY());
+                        me.consume();
+                    }
+                }
+            });
             setOnMouseReleased(new EventHandler<MouseEvent>() {
                 @Override public void handle(MouseEvent me) {
                     if (me.getButton().equals(MouseButton.MIDDLE)) {
@@ -1007,8 +1016,6 @@
                         }
                     } else if (me.getButton().equals(MouseButton.PRIMARY)) {
                         getBehavior().selectTab(getTab());
-                    } else if (me.getButton().equals(MouseButton.SECONDARY) && getTab().getContextMenu() != null) {
-                        getTab().getContextMenu().show(inner, me.getScreenX(), me.getScreenY());
                     }
                 }
             });
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableColumnHeader.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableColumnHeader.java	Thu Dec 01 11:33:58 2011 -0500
@@ -43,6 +43,7 @@
 import static javafx.scene.control.TableColumn.SortType.ASCENDING;
 import static javafx.scene.control.TableColumn.SortType.DESCENDING;
 import javafx.scene.control.TableView;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.GridPane;
 import javafx.scene.layout.HBox;
@@ -236,14 +237,19 @@
                 me.consume();
             }
         });
+        setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
+            @Override public void handle(ContextMenuEvent me) {
+                 ContextMenu menu = getTableColumn().getContextMenu();
+                 if (menu != null) {
+                     menu.show(TableColumnHeader.this, me.getScreenX(), me.getScreenY());
+                     me.consume();
+                }
+            }
+        });
         setOnMouseReleased(new EventHandler<MouseEvent>() {
             @Override public void handle(MouseEvent me) {
-                if (MouseEvent.impl_getPopupTrigger(me)) {
-                    ContextMenu menu = getTableColumn().getContextMenu();
-                    if (menu != null) {
-                        menu.show(TableColumnHeader.this, me.getScreenX(), me.getScreenY());
-                    }
-                } else if (getTableHeaderRow().isReordering() && isColumnReorderingEnabled()) {
+                if (MouseEvent.impl_getPopupTrigger(me)) return;
+                if (getTableHeaderRow().isReordering() && isColumnReorderingEnabled()) {
                     columnReorderingComplete(me);
                 } else {
                     sortColumn(getTableColumn(), me.isShiftDown());
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableHeaderRow.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableHeaderRow.java	Thu Dec 01 11:33:58 2011 -0500
@@ -45,6 +45,7 @@
 import javafx.scene.control.Label;
 import javafx.scene.control.TableColumn;
 import javafx.scene.control.TableView;
+import javafx.scene.input.ContextMenuEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.Region;
@@ -264,10 +265,11 @@
                 requestLayout();
             }
         });
-        cornerRegion.setOnMouseReleased(new EventHandler<MouseEvent>() {
-            @Override public void handle(MouseEvent me) {
+        cornerRegion.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
+            @Override public void handle(ContextMenuEvent me) {
                 // show a popupMenu which lists all columns
                 columnPopupMenu.show(cornerRegion, Side.BOTTOM, 0, 0);
+                me.consume();
             }
         });
 
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Thu Dec 01 11:33:58 2011 -0500
@@ -48,6 +48,7 @@
 import javafx.geometry.VerticalDirection;
 import javafx.scene.Group;
 import javafx.scene.Node;
+import javafx.scene.control.ContextMenu;
 import javafx.scene.control.IndexRange;
 import javafx.scene.control.ScrollPane;
 import javafx.scene.control.TextArea;
@@ -681,11 +682,15 @@
         return new Rectangle2D(x, y, width, height);
     }
 
-    @Override public void showContextMenu() {
-        Bounds caretBounds = caretPath.getLayoutBounds();
-        Point2D p = Utils.pointRelativeTo(contentView, null, caretBounds.getMinX(),
-                                          caretBounds.getMaxY(), false);
-        showContextMenu(p.getX(), p.getY());
+    @Override public boolean showContextMenu(ContextMenu menu, double x, double y, boolean isKeyboardTrigger) {
+        if (isKeyboardTrigger) {
+            Bounds caretBounds = caretPath.getLayoutBounds();
+            Point2D p = Utils.pointRelativeTo(contentView, null, caretBounds.getMinX(),
+                                              caretBounds.getMaxY(), false);
+            x = p.getX();
+            y = p.getY();
+        }
+        return super.showContextMenu(menu, x, y, isKeyboardTrigger);
     }
 
     @Override public void scrollCharacterToVisible(final int index) {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Thu Dec 01 12:59:24 2011 +1000
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Thu Dec 01 11:33:58 2011 -0500
@@ -47,6 +47,7 @@
 import javafx.geometry.Rectangle2D;
 import javafx.scene.Group;
 import javafx.scene.Node;
+import javafx.scene.control.ContextMenu;
 import javafx.scene.control.IndexRange;
 import javafx.scene.control.TextField;
 import javafx.scene.input.MouseEvent;
@@ -139,11 +140,15 @@
      */
     protected ObservableDoubleValue textRight;
 
-    @Override public void showContextMenu() {
-        Bounds caretBounds = caretPath.getLayoutBounds();
-        Point2D p = Utils.pointRelativeTo(textNode, null, caretBounds.getMinX(),
-                                          caretBounds.getMaxY(), false);
-        showContextMenu(p.getX(), p.getY());
+    @Override public boolean showContextMenu(ContextMenu menu, double x, double y, boolean isKeyboardTrigger) {
+        if (isKeyboardTrigger) {
+            Bounds caretBounds = caretPath.getLayoutBounds();
+            Point2D p = Utils.pointRelativeTo(textNode, null, caretBounds.getMinX(),
+                                              caretBounds.getMaxY(), false);
+            x = p.getX();
+            y = p.getY();
+        }
+        return super.showContextMenu(menu, x, y, isKeyboardTrigger);
     }
 
     /**