changeset 1329:a86b9a28478c

RT-22636: Fixed coordinates of keyboard-triggered ContextMenuEvent. RT-20936: Documented coordinates of ContextMenuEvent.
author Pavel Safrata
date Mon, 18 Jun 2012 16:06:46 +0200
parents 3525ca3b1439
children c9fe13cb7935
files javafx-ui-common/src/javafx/scene/Scene.java javafx-ui-common/src/javafx/scene/input/ContextMenuEvent.java javafx-ui-common/test/unit/javafx/scene/input/ContextMenuEventTest.java
diffstat 3 files changed, 177 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/javafx/scene/Scene.java	Mon Jun 18 10:30:06 2012 +0200
+++ b/javafx-ui-common/src/javafx/scene/Scene.java	Mon Jun 18 16:06:46 2012 +0200
@@ -110,6 +110,7 @@
 import javafx.beans.property.ReadOnlyDoubleWrapper;
 import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.beans.property.ReadOnlyObjectWrapper;
+import javafx.geometry.Bounds;
 import javafx.geometry.Orientation;
 import javafx.scene.image.WritableImage;
 import javafx.scene.input.GestureEvent;
@@ -1528,6 +1529,18 @@
         if (!isKeyboardTrigger) Scene.inMousePick = true;
         if (isKeyboardTrigger) {
             Node sceneFocusOwner = getFocusOwner();
+
+            // for keyboard triggers set coordinates inside focus owner
+            final Bounds bounds = sceneFocusOwner.localToScene(
+                    sceneFocusOwner.getBoundsInLocal());
+            final double xOffset = xAbs - x2;
+            final double yOffset = yAbs - y2;
+
+            x2 = bounds.getMinX() + bounds.getWidth() / 4;
+            y2 = bounds.getMinY() + bounds.getHeight() / 2;
+            xAbs = x2 + xOffset;
+            yAbs = y2 + yOffset;
+
             eventTarget = sceneFocusOwner != null ? sceneFocusOwner : Scene.this;
         } else {
             eventTarget = pick(x2, y2);
--- a/javafx-ui-common/src/javafx/scene/input/ContextMenuEvent.java	Mon Jun 18 10:30:06 2012 +0200
+++ b/javafx-ui-common/src/javafx/scene/input/ContextMenuEvent.java	Mon Jun 18 16:06:46 2012 +0200
@@ -40,6 +40,10 @@
  * menu is platform specific.  For example, on Windows, Shift+F10
  * requests a context menu.
  * <p>
+ * The event coordinates contain default position for the context menu.
+ * For mouse-triggered events it is the position of the
+ * mouse cursor, for keyboard-triggered events it is a point
+ * inside of bounds of current focus owner (which is the event's target).
  */
 public class ContextMenuEvent extends InputEvent {
 
@@ -112,20 +116,38 @@
 
     /**
      * Horizontal x position of the event relative to the
-     * origin of the MouseEvent's node.
+     * origin of the ContextMenuEvent's node.
      */
     private double x;
 
+    /**
+     * Horizontal position of the event relative to the
+     * origin of the ContextMenuEvent's source.
+     * For more information about this event's coordinate semantics please see
+     * the general description of {@link ContextMenuEvent}.
+     *
+     * @return horizontal position of the event relative to the
+     * origin of the ContextMenuEvent's source.
+     */
     public final double getX() {
         return x;
     }
 
     /**
      * Vertical y position of the event relative to the
-     * origin of the MouseEvent's node.
+     * origin of the ContextMenuEvent's node.
      */
     private double y;
 
+    /**
+     * Vertical position of the event relative to the
+     * origin of the ContextMenuEvent's source.
+     * For more information about this event's coordinate semantics please see
+     * the general description of {@link ContextMenuEvent}.
+     *
+     * @return vertical position of the event relative to the
+     * origin of the ContextMenuEvent's source.
+     */
     public final double getY() {
         return y;
     }
@@ -135,6 +157,12 @@
      */
     private double screenX;
 
+    /**
+     * Returns absolute horizontal position of the event.
+     * For more information about this event's coordinate semantics please see
+     * the general description of {@link ContextMenuEvent}.
+     * @return absolute horizontal position of the event
+     */
     public final double getScreenX() {
         return screenX;
     }
@@ -144,34 +172,66 @@
      */
     private double screenY;
 
+    /**
+     * Returns absolute vertical position of the event.
+     * For more information about this event's coordinate semantics please see
+     * the general description of {@link ContextMenuEvent}.
+     * @return absolute vertical position of the event
+     */
     public final double getScreenY() {
         return screenY;
     }
 
     /**
      * Horizontal x position of the event relative to the
-     * origin of the {@code Scene} that contains the MouseEvent's node.
+     * origin of the {@code Scene} that contains the ContextMenuEvent's node.
      * If the node is not in a {@code Scene}, then the value is relative to
-     * the boundsInParent of the root-most parent of the MouseEvent's node.
+     * the boundsInParent of the root-most parent of the ContextMenuEvent's node.
      */
     private double sceneX;
 
+    /**
+     * Returns horizontal position of the event relative to the
+     * origin of the {@code Scene} that contains the ContextMenuEvent's source.
+     * If the node is not in a {@code Scene}, then the value is relative to
+     * the boundsInParent of the root-most parent of the ContextMenuEvent's node.
+     * For more information about this event's coordinate semantics please see
+     * the general description of {@link ContextMenuEvent}.
+     *
+     * @return horizontal position of the event relative to the
+     * origin of the {@code Scene} that contains the ContextMenuEvent's source
+     */
     public final double getSceneX() {
         return sceneX;
     }
 
     /**
      * Vertical y position of the event relative to the
-     * origin of the {@code Scene} that contains the MouseEvent's node.
+     * origin of the {@code Scene} that contains the ContextMenuEvent's node.
      * If the node is not in a {@code Scene}, then the value is relative to
-     * the boundsInParent of the root-most parent of the MouseEvent's node.
+     * the boundsInParent of the root-most parent of the ContextMenuEvent's node.
      */
     private double sceneY;
 
+    /**
+     * Returns vertical position of the event relative to the
+     * origin of the {@code Scene} that contains the ContextMenuEvent's source.
+     * If the node is not in a {@code Scene}, then the value is relative to
+     * the boundsInParent of the root-most parent of the ContextMenuEvent's node.
+     * For more information about this event's coordinate semantics please see
+     * the general description of {@link ContextMenuEvent}.
+     *
+     * @return vertical position of the event relative to the
+     * origin of the {@code Scene} that contains the ContextMenuEvent's source
+     */
     public final double getSceneY() {
         return sceneY;
     }
 
+    /**
+     * Returns a string representation of this {@code ContextMenuEvent} object.
+     * @return a string representation of this {@code ContextMenuEvent} object.
+     */
     @Override public String toString() {
         final StringBuilder sb = new StringBuilder("ContextMenuEvent [");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/javafx/scene/input/ContextMenuEventTest.java	Mon Jun 18 16:06:46 2012 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010, 2012, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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 javafx.scene.input;
+
+import com.sun.javafx.pgstub.StubScene;
+import javafx.scene.Group;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.shape.Rectangle;
+import javafx.event.EventHandler;
+import javafx.stage.Stage;
+
+import org.junit.Test;
+
+public class ContextMenuEventTest {
+
+    @Test public void mouseTriggerKeepsCoordinates() {
+        Rectangle rect = new Rectangle(100, 100);
+        rect.setTranslateX(100);
+        rect.setTranslateY(100);
+        Group root = new Group(rect);
+        Scene scene = new Scene(root);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        rect.requestFocus();
+
+        rect.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
+            @Override public void handle(ContextMenuEvent event) {
+                assertEquals(1.0, event.getX(), 0.0001);
+                assertEquals(101, event.getSceneX(), 0.0001);
+                assertEquals(201, event.getScreenX(), 0.0001);
+                assertEquals(2.0, event.getY(), 0.0001);
+                assertEquals(102, event.getSceneY(), 0.0001);
+                assertEquals(202, event.getScreenY(), 0.0001);
+                assertFalse(event.isKeyboardTrigger());
+            }
+        });
+
+        ((StubScene) scene.impl_getPeer()).getListener().menuEvent(
+                101, 102, 201, 202, false);
+    }
+
+    @Test public void keyTriggerSetsCoordinatesToFocusOwner() {
+        Rectangle rect = new Rectangle(100, 100);
+        rect.setTranslateX(100);
+        rect.setTranslateY(100);
+        Group root = new Group(rect);
+        Scene scene = new Scene(root);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        rect.requestFocus();
+
+        rect.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
+            @Override public void handle(ContextMenuEvent event) {
+                assertEquals(25.0, event.getX(), 0.0001);
+                assertEquals(125, event.getSceneX(), 0.0001);
+                assertEquals(225, event.getScreenX(), 0.0001);
+                assertEquals(50.0, event.getY(), 0.0001);
+                assertEquals(150, event.getSceneY(), 0.0001);
+                assertEquals(250, event.getScreenY(), 0.0001);
+                assertTrue(event.isKeyboardTrigger());
+            }
+        });
+
+        ((StubScene) scene.impl_getPeer()).getListener().menuEvent(
+                101, 102, 201, 202, true);
+    }
+}