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

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

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2010, 2013, 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

@@ -25,111 +25,104 @@
 
 package com.sun.javafx.scene.control.behavior;
 
 import javafx.scene.control.ChoiceBox;
 import javafx.scene.control.SelectionModel;
+import com.sun.javafx.scene.control.skin.Utils;
+import com.sun.javafx.scene.control.inputmap.InputMap;
+import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
-import java.util.ArrayList;
-import java.util.List;
-import com.sun.javafx.scene.control.skin.Utils;
-import static javafx.scene.input.KeyCode.CANCEL;
-import static javafx.scene.input.KeyCode.DOWN;
-import static javafx.scene.input.KeyCode.ENTER;
-import static javafx.scene.input.KeyCode.ESCAPE;
-import static javafx.scene.input.KeyCode.SPACE;
-import static javafx.scene.input.KeyEvent.KEY_PRESSED;
-import static javafx.scene.input.KeyEvent.KEY_RELEASED;
+import static javafx.scene.input.KeyCode.*;
+
+import static com.sun.javafx.scene.control.inputmap.InputMap.KeyMapping;
 
 /**
  * ChoiceBoxBehavior - default implementation
- *
- * @profile common
  */
 public class ChoiceBoxBehavior<T> extends BehaviorBase<ChoiceBox<T>> {
-    /**
-     * The key bindings for the ChoiceBox. It seems this should really be the
-     * same as with the ButtonBehavior super class, but it doesn't handle ENTER
-     * events on desktop, whereas this does. It may be a proper analysis of the
-     * interaction logic would allow us to share bindings, but for now, we simply
-     * build it up specially here.
-     */
-    protected static final List<KeyBinding> CHOICE_BUTTON_BINDINGS = new ArrayList<KeyBinding>();
-    static {
-        CHOICE_BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_PRESSED, "Press"));
-        CHOICE_BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_RELEASED, "Release"));
-
-        if (Utils.isTwoLevelFocus()) {
-            CHOICE_BUTTON_BINDINGS.add(new KeyBinding(ENTER, KEY_PRESSED, "Press"));
-            CHOICE_BUTTON_BINDINGS.add(new KeyBinding(ENTER, KEY_RELEASED, "Release"));
-        }
 
-        CHOICE_BUTTON_BINDINGS.add(new KeyBinding(ESCAPE, KEY_RELEASED, "Cancel"));
-        CHOICE_BUTTON_BINDINGS.add(new KeyBinding(DOWN, KEY_RELEASED, "Down"));
-        CHOICE_BUTTON_BINDINGS.add(new KeyBinding(CANCEL, KEY_RELEASED, "Cancel"));
-
-    }
+    private final InputMap<ChoiceBox<T>> choiceBoxInputMap;
 
     private TwoLevelFocusComboBehavior tlFocus;
 
     /**************************************************************************
      *                          Setup KeyBindings                             *
      *************************************************************************/
-    @Override protected void callAction(String name) {
-        if (name.equals("Cancel")) cancel();
-        else if (name.equals("Press")) keyPressed();
-        else if (name.equals("Release")) keyReleased();
-        else if (name.equals("Down")) showPopup();
-        else super.callAction(name);
-    }
 
     public ChoiceBoxBehavior(ChoiceBox<T> control) {
-        super(control, CHOICE_BUTTON_BINDINGS);
+        super(control);
+
+        // create a map for choiceBox-specific mappings (this reuses the default
+        // InputMap installed on the control, if it is non-null, allowing us to pick up any user-specified mappings)
+        choiceBoxInputMap = createInputMap();
+
+        // choiceBox-specific mappings for key and mouse input
+        addDefaultMapping(choiceBoxInputMap,
+            new KeyMapping(SPACE, KeyEvent.KEY_PRESSED, this::keyPressed),
+            new KeyMapping(SPACE, KeyEvent.KEY_RELEASED, this::keyReleased),
+
+            new KeyMapping(ESCAPE, KeyEvent.KEY_RELEASED, e -> cancel()),
+            new KeyMapping(DOWN, KeyEvent.KEY_RELEASED, e -> showPopup()),
+            new KeyMapping(CANCEL, KeyEvent.KEY_RELEASED, e -> cancel())
+        );
+
+        // add some special two-level focus mappings
+        InputMap<ChoiceBox<T>> twoLevelFocusInputMap = new InputMap<>(control);
+        twoLevelFocusInputMap.setInterceptor(e -> !Utils.isTwoLevelFocus());
+        twoLevelFocusInputMap.getMappings().addAll(
+            new KeyMapping(ENTER, KeyEvent.KEY_PRESSED, this::keyPressed),
+            new KeyMapping(ENTER, KeyEvent.KEY_RELEASED, this::keyReleased)
+        );
+        addDefaultChildMap(choiceBoxInputMap, twoLevelFocusInputMap);
+
         // Only add this if we're on an embedded platform that supports 5-button navigation
         if (Utils.isTwoLevelFocus()) {
             tlFocus = new TwoLevelFocusComboBehavior(control); // needs to be last.
         }
     }
 
+    @Override public InputMap<ChoiceBox<T>> getInputMap() {
+        return choiceBoxInputMap;
+    }
+
     @Override public void dispose() {
         if (tlFocus != null) tlFocus.dispose();
         super.dispose();
     }
 
     public void select(int index) {
-        SelectionModel<T> sm = getControl().getSelectionModel();
+        SelectionModel<T> sm = getNode().getSelectionModel();
         if (sm == null) return;
 
         sm.select(index);
     }
 
     public void close() {
-        getControl().hide();
+        getNode().hide();
     }
 
     public void showPopup() {
-        getControl().show();
+        getNode().show();
     }
 
     /**
      * Invoked when a mouse press has occurred over the box. In addition to
      * potentially arming the Button, this will transfer focus to the box
      */
-    @Override public void mousePressed(MouseEvent e) {
-        ChoiceBox<T> choiceButton = getControl();
-        super.mousePressed(e);
+    public void mousePressed(MouseEvent e) {
+        ChoiceBox<T> choiceButton = getNode();
         if (choiceButton.isFocusTraversable()) choiceButton.requestFocus();
     }
 
     /**
      * Invoked when a mouse release has occurred. We determine whether this
      * was done in a manner that would fire the box's action. This happens
      * only if the box was armed by a corresponding mouse press.
      */
-    @Override public void mouseReleased(MouseEvent e) {
-        ChoiceBox<T> choiceButton = getControl();
-        super.mouseReleased(e);
+    public void mouseReleased(MouseEvent e) {
+        ChoiceBox<T> choiceButton = getNode();
         if (choiceButton.isShowing() || !choiceButton.contains(e.getX(), e.getY())) {
             choiceButton.hide(); // hide if already showing 
         }
         else if (e.getButton() == MouseButton.PRIMARY) {
             choiceButton.show();

@@ -139,29 +132,29 @@
     /**
      * This function is invoked when an appropriate keystroke occurs which
      * causes this box to be armed if it is not already armed by a mouse
      * press.
      */
-    private void keyPressed() {
-        ChoiceBox<T> choiceButton = getControl();
+    private void keyPressed(KeyEvent e) {
+        ChoiceBox<T> choiceButton = getNode();
         if (!choiceButton.isShowing()) {
             choiceButton.show();
         }
     }
 
     /**
      * Invoked when a valid keystroke release occurs which causes the box
      * to fire if it was armed by a keyPress.
      */
-    private void keyReleased() {
+    private void keyReleased(KeyEvent e) {
     }
 
     // no-op
     /**
      * Invoked when "escape" key is released
      */
     public void cancel() {
-        ChoiceBox<T> choiceButton = getControl();
+        ChoiceBox<T> choiceButton = getNode();
         choiceButton.hide();
     }
 
 }