diff -r 2e234ddc0c29 javafx-ui-common/src/com/sun/javafx/scene/EventHandlerProperties.java --- a/javafx-ui-common/src/com/sun/javafx/scene/EventHandlerProperties.java Mon Nov 28 12:24:42 2011 -0500 +++ b/javafx-ui-common/src/com/sun/javafx/scene/EventHandlerProperties.java Mon Nov 28 14:33:16 2011 -0500 @@ -9,6 +9,7 @@ import javafx.event.Event; import javafx.event.EventHandler; import javafx.event.EventType; +import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.DragEvent; import javafx.scene.input.InputMethodEvent; import javafx.scene.input.KeyEvent; @@ -28,6 +29,24 @@ this.eventDispatcher = eventDispatcher; this.bean = bean; } + + private EventHandlerProperty onMenuContextRequested; + + public final EventHandler onContextMenuRequested() { + return (onMenuContextRequested == null) ? null : onMenuContextRequested.get(); + } + + public ObjectProperty> + onContextMenuRequestedProperty() { + if (onMenuContextRequested == null) { + onMenuContextRequested = new EventHandlerProperty( + bean, + "onMenuContextRequested", + ContextMenuEvent.CONTEXT_MENU_REQUESTED); + } + return onMenuContextRequested; + } + private EventHandlerProperty onMouseClicked; diff -r 2e234ddc0c29 javafx-ui-common/src/com/sun/javafx/tk/TKSceneListener.java --- a/javafx-ui-common/src/com/sun/javafx/tk/TKSceneListener.java Mon Nov 28 12:24:42 2011 -0500 +++ b/javafx-ui-common/src/com/sun/javafx/tk/TKSceneListener.java Mon Nov 28 14:33:16 2011 -0500 @@ -76,4 +76,7 @@ boolean _shiftDown, boolean _controlDown, boolean _altDown, boolean _metaDown); + public void menuEvent(double x, double y, double xAbs, double yAbs, + boolean isKeyboardTrigger); + } diff -r 2e234ddc0c29 javafx-ui-common/src/javafx/scene/Node.java --- a/javafx-ui-common/src/javafx/scene/Node.java Mon Nov 28 12:24:42 2011 -0500 +++ b/javafx-ui-common/src/javafx/scene/Node.java Mon Nov 28 14:33:16 2011 -0500 @@ -40,6 +40,7 @@ import javafx.scene.effect.Blend; import javafx.scene.effect.BlendMode; import javafx.scene.effect.Effect; +import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; import javafx.scene.input.InputEvent; @@ -4966,6 +4967,27 @@ return pressed; } + public final void setOnContextMenuRequested( + EventHandler value) { + onContextMenuRequestedProperty().set(value); + } + + public final EventHandler getOnContextMenuRequested() { + return (eventHandlerProperties == null) + ? null : eventHandlerProperties.onContextMenuRequested(); + } + + /** + * Defines a function to be called when a context menu + * has been requested on this {@code Node}. + * + * @profile common + */ + public final ObjectProperty> + onContextMenuRequestedProperty() { + return getEventHandlerProperties().onContextMenuRequestedProperty(); + } + public final void setOnMouseClicked( EventHandler value) { onMouseClickedProperty().set(value); diff -r 2e234ddc0c29 javafx-ui-common/src/javafx/scene/Scene.java --- a/javafx-ui-common/src/javafx/scene/Scene.java Mon Nov 28 12:24:42 2011 -0500 +++ b/javafx-ui-common/src/javafx/scene/Scene.java Mon Nov 28 14:33:16 2011 -0500 @@ -37,6 +37,7 @@ import javafx.event.EventTarget; import javafx.event.EventType; import javafx.geometry.Point2D; +import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; import javafx.scene.input.InputMethodEvent; @@ -1278,6 +1279,24 @@ mouseHandler.process(e); } + /** + * @treatasprivate implementation detail + * @deprecated This is an internal API that is not intended for use and will be removed in the next version + */ + @Deprecated + public void impl_processMenuEvent(double x2, double y2, double xAbs, double yAbs, + boolean isKeyboardTrigger) { + + //TODO - should the event go to the node that is picked or always the focus owner + final Node sceneFocusOwner = keyHandler.getFocusOwner(); + final EventTarget eventTarget = + (sceneFocusOwner != null) ? sceneFocusOwner + : Scene.this; + ContextMenuEvent context = ContextMenuEvent.impl_contextEvent( + x2, y2, xAbs, yAbs, isKeyboardTrigger, ContextMenuEvent.CONTEXT_MENU_REQUESTED); + Event.fireEvent(eventTarget, context); + } + private void processScrollEvent(ScrollEvent e) { EventTarget pickedTarget = null; @@ -1931,6 +1950,12 @@ x, y, screenX, screenY, _shiftDown, _controlDown, _altDown, _metaDown)); } + + @Override + public void menuEvent(double x, double y, double xAbs, double yAbs, + boolean isKeyboardTrigger) { + Scene.this.impl_processMenuEvent(x, y, xAbs,yAbs, isKeyboardTrigger); + } } @@ -3373,6 +3398,52 @@ return tail; } + + /*************************************************************************** + * * + * Context Menus * + * * + **************************************************************************/ + + /** + * Defines a function to be called when a mouse button has been clicked + * (pressed and released) on this {@code Scene}. + * + * @profile common + */ + + private ObjectProperty> onContextMenuRequested; + + public final void setOnContextMenuRequested(EventHandler value) { + onContextMenuRequestedProperty().set(value); + } + + public final EventHandler getOnContextMenuRequested() { + return onContextMenuRequested == null ? null : onContextMenuRequested.get(); + } + + public final ObjectProperty> onContextMenuRequestedProperty() { + if (onContextMenuRequested == null) { + onContextMenuRequested = new ObjectPropertyBase>() { + + @Override + protected void invalidated() { + setEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, get()); + } + + @Override + public Object getBean() { + return Scene.this; + } + + @Override + public String getName() { + return "onContextMenuRequested"; + } + }; + } + return onContextMenuRequested; + } /*************************************************************************** * * diff -r 2e234ddc0c29 javafx-ui-common/src/javafx/scene/input/ContextMenuEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-ui-common/src/javafx/scene/input/ContextMenuEvent.java Mon Nov 28 14:33:16 2011 -0500 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved + */ + + +package javafx.scene.input; + +import com.sun.javafx.scene.input.InputEventUtils; +import javafx.event.Event; +import javafx.event.EventTarget; +import javafx.event.EventType; +import javafx.geometry.Point2D; + +// PENDING_DOC_REVIEW +/** + * When the user requests a context menu, this event occurs. Context + * menus can be triggered by the mouse or the keyboard. The exact + * sequence of mouse or keyboard events that is used to request a + * menu is platform specific. For example, on Windows, Shift+F10 + * requests a context menu. + *

+ * + * @profile common + */ +public class ContextMenuEvent extends InputEvent { + + /** + * This event occurs when a context menu is requested. + */ + public static final EventType CONTEXT_MENU_REQUESTED = + new EventType(ContextMenuEvent.ANY, "CONTEXT_MENU_REQUESTED"); + + private ContextMenuEvent(final EventType eventType) { + super(eventType); + } + + /** + * @treatasprivate implementation detail + */ + public static ContextMenuEvent impl_contextEvent(double _x, double _y, + double _screenX, double _screenY, boolean _keyboardTrigger, + EventType _eventType + ) + { + ContextMenuEvent e = new ContextMenuEvent(_eventType); + e.x = _x; + e.y = _y; + e.screenX = _screenX; + e.screenY = _screenY; + e.sceneX = _x; + e.sceneY = _y; + e.keyboardTrigger = _keyboardTrigger; + return e; + } + + /** + * Fills the given event by this event's coordinates recomputed to the given + * source object + * @param newEvent Event whose coordinates are to be filled + * @param newSource Source object to compute coordinates for + */ + private void recomputeCoordinatesToSource(ContextMenuEvent newEvent, Object newSource) { + + final Point2D newCoordinates = InputEventUtils.recomputeCoordinates( + new Point2D(x, y), source, newSource); + + newEvent.x = newCoordinates.getX(); + newEvent.y = newCoordinates.getY(); + newEvent.sceneX = getSceneX(); + newEvent.sceneY = getSceneY(); + } + + @Override + public Event copyFor(Object newSource, EventTarget newTarget) { + ContextMenuEvent e = (ContextMenuEvent) super.copyFor(newSource, newTarget); + recomputeCoordinatesToSource(e, newSource); + return e; + } + + /** + * The boolean that indicates the event was triggered by a keyboard gesture. + * + * @profile common + */ + private boolean keyboardTrigger; + + /** + * Determines whether this event originated from the keyboard. + * + * @return true if the event was caused by the keyboard + */ + public boolean isKeyboardTrigger() { + return keyboardTrigger; + } + + /** + * Horizontal x position of the event relative to the + * origin of the MouseEvent's node. + * + * @profile common + */ + private double x; + + public final double getX() { + return x; + } + + /** + * Vertical y position of the event relative to the + * origin of the MouseEvent's node. + * + * @profile common + */ + private double y; + + public final double getY() { + return y; + } + + /** + * Absolute horizontal x position of the event. + * + * @profile common + */ + private double screenX; + + public final double getScreenX() { + return screenX; + } + + /** + * Absolute vertical y position of the event. + * + * @profile common + */ + private double screenY; + + 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. + * 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. + * + * @profile common + */ + private double sceneX; + + 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. + * 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. + * + * @profile common + */ + private double sceneY; + + public final double getSceneY() { + return sceneY; + } + + @Override public String toString() { + final StringBuilder sb = new StringBuilder("ContextMenuEvent ["); + + sb.append("source = ").append(getSource()); + sb.append(", target = ").append(getTarget()); + sb.append(", eventType = ").append(getEventType()); + sb.append(", consumed = ").append(isConsumed()); + + sb.append(", x = ").append(getX()).append(", y = ").append(getY()); + + return sb.append("]").toString(); + } +} diff -r 2e234ddc0c29 javafx-ui-quantum/src/com/sun/javafx/tk/quantum/GlassViewEventHandler.java --- a/javafx-ui-quantum/src/com/sun/javafx/tk/quantum/GlassViewEventHandler.java Mon Nov 28 12:24:42 2011 -0500 +++ b/javafx-ui-quantum/src/com/sun/javafx/tk/quantum/GlassViewEventHandler.java Mon Nov 28 14:33:16 2011 -0500 @@ -231,6 +231,33 @@ } } + @Override public void handleMenuEvent(View view, int x, int y, int xAbs, int yAbs, boolean isKeyboardTrigger) + { + if (toolkit() == false) { + return; + } + WindowStage stage = scene.getWindowStage(); + try { + stage.setInEventHandler(true); + if (scene.sceneListener != null) { + scene.sceneListener.menuEvent(x, y, xAbs, yAbs, isKeyboardTrigger); + } + } catch (RuntimeException ex) { + if (verbose) { + ex.printStackTrace(); + } + throw ex; + } catch (Throwable t) { + if (verbose) { + t.printStackTrace(); + } + throw new RuntimeException(t); + } + finally { + stage.setInEventHandler(false); + } + } + @Override public void handleScrollEvent(View view, long time, int x, int y, int xAbs, int yAbs, double deltaX, double deltaY, int modifiers,