--- old/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ContextMenuSkin.java 2015-09-03 15:19:05.809531100 -0700 +++ /dev/null 2015-09-03 15:19:06.000000000 -0700 @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2010, 2014, 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 com.sun.javafx.scene.control.skin; - -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.scene.AccessibleAttribute; -import javafx.scene.Node; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Menu; -import javafx.scene.control.Skin; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.Region; -import javafx.stage.WindowEvent; -import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior; - -/** - * Default Skin implementation for PopupMenu. Several controls use PopupMenu in - * order to display items in a drop down. It deals mostly with show hide logic for - * Popup based controls, and specifically in this case for PopupMenu. This is - * explained in the superclass {@link PopupControlSkin}. - *

- * Region/css based skin implementation for PopupMenu is the {@link PopupMenuContent} - * class. - */ -public class ContextMenuSkin implements Skin { - - /* need to hold a reference to popupMenu here because getSkinnable() deliberately - * returns null in PopupControlSkin. */ - private ContextMenu popupMenu; - - private final Region root; - private TwoLevelFocusPopupBehavior tlFocus; - - // Fix for RT-18247 - private final EventHandler keyListener = new EventHandler() { - @Override public void handle(KeyEvent event) { - if (event.getEventType() != KeyEvent.KEY_PRESSED) return; - - // We only care if the root container still has focus - if (! root.isFocused()) return; - - final KeyCode code = event.getCode(); - switch (code) { - case ENTER: - case SPACE: popupMenu.hide(); return; - default: return; - } - } - }; - - /***/ - public ContextMenuSkin(final ContextMenu popupMenu) { - this.popupMenu = popupMenu; - - // When a contextMenu is shown, requestFocus on its content to enable - // keyboard navigation. - popupMenu.addEventHandler(Menu.ON_SHOWN, new EventHandler() { - @Override public void handle(Event event) { - Node cmContent = popupMenu.getSkin().getNode(); - if (cmContent != null) { - cmContent.requestFocus(); - if (cmContent instanceof ContextMenuContent) { - Node accMenu = ((ContextMenuContent)cmContent).getItemsContainer(); - accMenu.notifyAccessibleAttributeChanged(AccessibleAttribute.VISIBLE); - } - } - - root.addEventHandler(KeyEvent.KEY_PRESSED, keyListener); - } - }); - popupMenu.addEventHandler(Menu.ON_HIDDEN, new EventHandler() { - @Override public void handle(Event event) { - Node cmContent = popupMenu.getSkin().getNode(); - if (cmContent != null) cmContent.requestFocus(); - - root.removeEventHandler(KeyEvent.KEY_PRESSED, keyListener); - } - }); - - // For accessibility Menu.ON_HIDING does not work because isShowing is true - // during the event, Menu.ON_HIDDEN does not work because the Window (in glass) - // has already being disposed. The fix is to use WINDOW_HIDING (WINDOW_HIDDEN). - popupMenu.addEventFilter(WindowEvent.WINDOW_HIDING, new EventHandler() { - @Override public void handle(Event event) { - Node cmContent = popupMenu.getSkin().getNode(); - if (cmContent instanceof ContextMenuContent) { - Node accMenu = ((ContextMenuContent)cmContent).getItemsContainer(); - accMenu.notifyAccessibleAttributeChanged(AccessibleAttribute.VISIBLE); - } - } - }); - - if (BehaviorSkinBase.IS_TOUCH_SUPPORTED && - popupMenu.getStyleClass().contains("text-input-context-menu")) { - root = new EmbeddedTextContextMenuContent(popupMenu); - } else { - root = new ContextMenuContent(popupMenu); - } - root.idProperty().bind(popupMenu.idProperty()); - root.styleProperty().bind(popupMenu.styleProperty()); - root.getStyleClass().addAll(popupMenu.getStyleClass()); // TODO needs to handle updates - - // Only add this if we're on an embedded platform that supports 5-button navigation - if (Utils.isTwoLevelFocus()) { - tlFocus = new TwoLevelFocusPopupBehavior(popupMenu); // needs to be last. - } - } - - @Override public ContextMenu getSkinnable() { - return popupMenu; - } - - @Override public Node getNode() { - return root; - } - - @Override public void dispose() { - root.idProperty().unbind(); - root.styleProperty().unbind(); - if (tlFocus != null) tlFocus.dispose(); - } -} --- /dev/null 2015-09-03 15:19:07.000000000 -0700 +++ new/modules/controls/src/main/java/javafx/scene/control/skin/ContextMenuSkin.java 2015-09-03 15:19:05.076489200 -0700 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2010, 2014, 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.control.skin; + +import com.sun.javafx.scene.control.ContextMenuContent; +import com.sun.javafx.scene.control.EmbeddedTextContextMenuContent; +import com.sun.javafx.scene.control.Properties; +import com.sun.javafx.scene.control.skin.Utils; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.scene.AccessibleAttribute; +import javafx.scene.Node; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.Control; +import javafx.scene.control.Menu; +import javafx.scene.control.Skin; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.Region; +import javafx.stage.WindowEvent; +import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior; + +/** + * Default Skin implementation for ContextMenu. Several controls use ContextMenu in + * order to display items in a drop down. This class mostly deals mostly with + * show / hide logic - the actual content of the context menu is contained within + * the {@link #getNode() root node}. + * + * @since 9 + * @see ContextMenu + */ +public class ContextMenuSkin implements Skin { + + /*************************************************************************** + * * + * Private fields * + * * + **************************************************************************/ + + /* need to hold a reference to popupMenu here because getSkinnable() deliberately + * returns null in PopupControlSkin. */ + private ContextMenu popupMenu; + + private final Region root; + private TwoLevelFocusPopupBehavior tlFocus; + + + + /*************************************************************************** + * * + * Listeners * + * * + **************************************************************************/ + + // Fix for RT-18247 + private final EventHandler keyListener = new EventHandler() { + @Override public void handle(KeyEvent event) { + if (event.getEventType() != KeyEvent.KEY_PRESSED) return; + + // We only care if the root container still has focus + if (! root.isFocused()) return; + + final KeyCode code = event.getCode(); + switch (code) { + case ENTER: + case SPACE: popupMenu.hide(); return; + default: return; + } + } + }; + + + + /*************************************************************************** + * * + * Constructors * + * * + **************************************************************************/ + + /** + * Creates a new ContextMenuSkin instance. + * + * @param control The control that this skin should be installed onto. + */ + public ContextMenuSkin(final ContextMenu control) { + this.popupMenu = control; + + // When a contextMenu is shown, requestFocus on its content to enable + // keyboard navigation. + popupMenu.addEventHandler(Menu.ON_SHOWN, new EventHandler() { + @Override public void handle(Event event) { + Node cmContent = popupMenu.getSkin().getNode(); + if (cmContent != null) { + cmContent.requestFocus(); + if (cmContent instanceof ContextMenuContent) { + Node accMenu = ((ContextMenuContent)cmContent).getItemsContainer(); + accMenu.notifyAccessibleAttributeChanged(AccessibleAttribute.VISIBLE); + } + } + + root.addEventHandler(KeyEvent.KEY_PRESSED, keyListener); + } + }); + popupMenu.addEventHandler(Menu.ON_HIDDEN, new EventHandler() { + @Override public void handle(Event event) { + Node cmContent = popupMenu.getSkin().getNode(); + if (cmContent != null) cmContent.requestFocus(); + + root.removeEventHandler(KeyEvent.KEY_PRESSED, keyListener); + } + }); + + // For accessibility Menu.ON_HIDING does not work because isShowing is true + // during the event, Menu.ON_HIDDEN does not work because the Window (in glass) + // has already being disposed. The fix is to use WINDOW_HIDING (WINDOW_HIDDEN). + popupMenu.addEventFilter(WindowEvent.WINDOW_HIDING, new EventHandler() { + @Override public void handle(Event event) { + Node cmContent = popupMenu.getSkin().getNode(); + if (cmContent instanceof ContextMenuContent) { + Node accMenu = ((ContextMenuContent)cmContent).getItemsContainer(); + accMenu.notifyAccessibleAttributeChanged(AccessibleAttribute.VISIBLE); + } + } + }); + + if (Properties.IS_TOUCH_SUPPORTED && + popupMenu.getStyleClass().contains("text-input-context-menu")) { + root = new EmbeddedTextContextMenuContent(popupMenu); + } else { + root = new ContextMenuContent(popupMenu); + } + root.idProperty().bind(popupMenu.idProperty()); + root.styleProperty().bind(popupMenu.styleProperty()); + root.getStyleClass().addAll(popupMenu.getStyleClass()); // TODO needs to handle updates + + // Only add this if we're on an embedded platform that supports 5-button navigation + if (Utils.isTwoLevelFocus()) { + tlFocus = new TwoLevelFocusPopupBehavior(popupMenu); // needs to be last. + } + } + + + + /*************************************************************************** + * * + * Public API * + * * + **************************************************************************/ + + /** {@inheritDoc} */ + @Override public ContextMenu getSkinnable() { + return popupMenu; + } + + /** {@inheritDoc} */ + @Override public Node getNode() { + return root; + } + + /** {@inheritDoc} */ + @Override public void dispose() { + root.idProperty().unbind(); + root.styleProperty().unbind(); + if (tlFocus != null) tlFocus.dispose(); + } +}