--- old/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/MenuButtonBehaviorBase.java 2015-09-03 14:48:17.842833500 -0700 +++ new/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/MenuButtonBehaviorBase.java 2015-09-03 14:48:17.246799400 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, 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 @@ -25,91 +25,73 @@ package com.sun.javafx.scene.control.behavior; -import static javafx.scene.input.KeyCode.UP; -import static javafx.scene.input.KeyCode.DOWN; -import static javafx.scene.input.KeyCode.LEFT; -import static javafx.scene.input.KeyCode.RIGHT; -import static javafx.scene.input.KeyCode.CANCEL; -import static javafx.scene.input.KeyCode.ESCAPE; -import static javafx.scene.input.KeyEvent.KEY_PRESSED; - -import java.util.ArrayList; -import java.util.List; - -import javafx.geometry.NodeOrientation; import javafx.geometry.Side; import javafx.scene.control.MenuButton; +import com.sun.javafx.scene.control.inputmap.InputMap; +import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; +import static com.sun.javafx.scene.control.inputmap.InputMap.KeyMapping; +import static javafx.scene.input.KeyCode.*; + /** * The base behavior for a MenuButton. */ public abstract class MenuButtonBehaviorBase extends ButtonBehavior { + private final InputMap buttonInputMap; + /*************************************************************************** * * * Constructors * * * **************************************************************************/ - public MenuButtonBehaviorBase(final C menuButton, List bindings) { - super(menuButton, bindings); + public MenuButtonBehaviorBase(final C menuButton) { + super(menuButton); + + // pull down the parent input map, no need to add focus traversal + // mappings - added in ButtonBehavior. + buttonInputMap = super.getInputMap(); + + // We want to remove the maping for MOUSE_RELEASED, as the event is + // handled by the skin instead, which calls the mouseReleased method below. + removeMapping(MouseEvent.MOUSE_RELEASED); + + /** + * The base key bindings for a MenuButton. These basically just define the + * bindings to close an open menu. Subclasses will tell you what can be done + * to open it. + */ + addDefaultMapping(new KeyMapping(ESCAPE, e -> getNode().hide())); + addDefaultMapping(new KeyMapping(CANCEL, e -> getNode().hide())); + + // we create a child input map, as we want to override some of the + // focus traversal behaviors (and child maps take precedence over parent maps) + InputMap customFocusInputMap = new InputMap<>(menuButton); + addDefaultMapping(customFocusInputMap, new KeyMapping(UP, this::overrideTraversalInput)); + addDefaultMapping(customFocusInputMap, new KeyMapping(DOWN, this::overrideTraversalInput)); + addDefaultMapping(customFocusInputMap, new KeyMapping(LEFT, this::overrideTraversalInput)); + addDefaultMapping(customFocusInputMap, new KeyMapping(RIGHT, this::overrideTraversalInput)); + addDefaultChildMap(buttonInputMap, customFocusInputMap); } + /*************************************************************************** * * * Key event handling * * * **************************************************************************/ - /** - * Opens the popup menu. - */ - protected static final String OPEN_ACTION = "Open"; - - /** - * Closes the popup menu. - */ - protected static final String CLOSE_ACTION = "Close"; - - /** - * The base key bindings for a MenuButton. These basically just define the - * bindings to close an open menu. Subclasses will tell you what can be done - * to open it. - */ - protected static final List BASE_MENU_BUTTON_BINDINGS = new ArrayList(); - static { - BASE_MENU_BUTTON_BINDINGS.add(new KeyBinding(UP, "TraverseUp")); - BASE_MENU_BUTTON_BINDINGS.add(new KeyBinding(DOWN, "TraverseDown")); - BASE_MENU_BUTTON_BINDINGS.add(new KeyBinding(LEFT, "TraverseLeft")); - BASE_MENU_BUTTON_BINDINGS.add(new KeyBinding(RIGHT, "TraverseRight")); - BASE_MENU_BUTTON_BINDINGS.add(new KeyBinding(ESCAPE, KEY_PRESSED, CLOSE_ACTION)); - BASE_MENU_BUTTON_BINDINGS.add(new KeyBinding(CANCEL, KEY_PRESSED, CLOSE_ACTION)); - } - - /** - * Invokes the given named action. - * - * @param name the name of the action to invoke - */ - @Override protected void callAction(String name) { - MenuButton button = getControl(); - Side popupSide = button.getPopupSide(); - - if (CLOSE_ACTION.equals(name)) { - button.hide(); - } else if (OPEN_ACTION.equals(name)) { - if (button.isShowing()) { - button.hide(); - } else { - button.show(); - } - } else if (!button.isShowing() && - ("TraverseUp".equals(name) && popupSide == Side.TOP) || - ("TraverseDown".equals(name) && (popupSide == Side.BOTTOM || popupSide == Side.TOP)) || - ("TraverseLeft".equals(name) && (popupSide == Side.RIGHT || popupSide == Side.LEFT)) || - ("TraverseRight".equals(name) && (popupSide == Side.RIGHT || popupSide == Side.LEFT))) { + private void overrideTraversalInput(KeyEvent event) { + final MenuButton button = getNode(); + final Side popupSide = button.getPopupSide(); + if (!button.isShowing() && + (event.getCode() == UP && popupSide == Side.TOP) || + (event.getCode() == DOWN && (popupSide == Side.BOTTOM || popupSide == Side.TOP)) || + (event.getCode() == LEFT && (popupSide == Side.RIGHT || popupSide == Side.LEFT)) || + (event.getCode() == RIGHT && (popupSide == Side.RIGHT || popupSide == Side.LEFT))) { // Show the menu when arrow key matches the popupSide // direction -- but also allow RIGHT key for LEFT position and // DOWN key for TOP position. To be symmetrical, we also allow for @@ -117,8 +99,14 @@ // because the skin only paints right- and down-facing arrows in // these cases. button.show(); + } + } + + protected void openAction() { + if (getNode().isShowing()) { + getNode().hide(); } else { - super.callAction(name); + getNode().show(); } } @@ -136,7 +124,7 @@ * @param behaveLikeButton if true, this should act just like a button */ public void mousePressed(MouseEvent e, boolean behaveLikeButton) { - final C control = getControl(); + final C control = getNode(); /* * Behaving like a button is easy - we just call super. But, we cannot @@ -165,12 +153,6 @@ } } - @Override public void mouseReleased(MouseEvent e) { - // Overriding to not call fire() on mouseReleased. - // The event is handled by the skin instead, which calls - // the method below. - } - /** * Handles mouse release events. This will be called by the skin. * @@ -181,10 +163,10 @@ if (behaveLikeButton) { super.mouseReleased(e); } else { - if (getControl().isShowing() && !getControl().contains(e.getX(), e.getY())) { - getControl().hide(); + if (getNode().isShowing() && !getNode().contains(e.getX(), e.getY())) { + getNode().hide(); } - getControl().disarm(); + getNode().disarm(); } } }