modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/MenuButtonBehaviorBase.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization

@@ -1,7 +1,7 @@
 /*
- * 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,104 +23,92 @@
  * questions.
  */
 
 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<C extends MenuButton> extends ButtonBehavior<C> {
 
-    /***************************************************************************
-     *                                                                         *
-     * Constructors                                                            *
-     *                                                                         *
-     **************************************************************************/
-
-    public MenuButtonBehaviorBase(final C menuButton, List<KeyBinding> bindings) {
-        super(menuButton, bindings);
-    }
+    private final InputMap<C> buttonInputMap;
 
     /***************************************************************************
      *                                                                         *
-     * Key event handling                                                      *
+     * Constructors                                                            *
      *                                                                         *
      **************************************************************************/
 
-    /**
-     * Opens the popup menu.
-     */
-    protected static final String OPEN_ACTION = "Open";
+    public MenuButtonBehaviorBase(final C menuButton) {
+        super(menuButton);
 
-    /**
-     * Closes the popup menu.
-     */
-    protected static final String CLOSE_ACTION = "Close";
+        // 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.
      */
-    protected static final List<KeyBinding> BASE_MENU_BUTTON_BINDINGS = new ArrayList<KeyBinding>();
-    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));
-    }
+        addDefaultMapping(new KeyMapping(ESCAPE, e -> getNode().hide()));
+        addDefaultMapping(new KeyMapping(CANCEL, e -> getNode().hide()));
 
-    /**
-     * 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();
+        // 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<C> 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);
             }
-        } 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))) {
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Key event handling                                                      *
+     *                                                                         *
+     **************************************************************************/
+
+    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
             // the LEFT key to work when in the RIGHT position. This is needed
             // 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();
         }
     }
 
     /***************************************************************************
      *                                                                         *

@@ -134,11 +122,11 @@
      *
      * @param e the mouse press event
      * @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
          * call super if all we want to do is show the popup. The reason for
          * this is that super also handles all the arm/disarm/fire logic, and

@@ -163,28 +151,22 @@
                 }
             }
         }
     }
 
-    @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.
      *
      * @param e the mouse press event
      * @param behaveLikeButton if true, this should act just like a button
      */
     public void mouseReleased(MouseEvent e, boolean behaveLikeButton) {
         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();
         }
     }
 }