modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ButtonBehavior.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
@@ -20,146 +20,160 @@
*
* 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.behavior;
+import javafx.beans.Observable;
import javafx.scene.control.ButtonBase;
+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 static javafx.scene.input.KeyCode.SPACE;
-import static javafx.scene.input.KeyCode.TAB;
-import static javafx.scene.input.KeyEvent.KEY_PRESSED;
-import static javafx.scene.input.KeyEvent.KEY_RELEASED;
+import static com.sun.javafx.scene.control.inputmap.InputMap.*;
+import static javafx.scene.input.KeyCode.SPACE;
/**
* All of the "button" types (CheckBox, RadioButton, ToggleButton, and Button)
* and also maybe some other types like hyperlinks operate on the "armed"
* selection strategy, just like JButton. This behavior class encapsulates that
* logic in a way that can be reused and extended by each of the individual
* class behaviors.
*
*/
public class ButtonBehavior<C extends ButtonBase> extends BehaviorBase<C> {
+ private final InputMap<C> buttonInputMap;
+
+ /**
+ * Indicates that a keyboard key has been pressed which represents the
+ * event (this could be space bar for example). As long as keyDown is true,
+ * we are also armed, and will ignore mouse events related to arming.
+ * Note this is made package private solely for the sake of testing.
+ */
+ private boolean keyDown;
+
+
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
- public ButtonBehavior(final C button) {
- super(button, BUTTON_BINDINGS);
+ public ButtonBehavior(C control) {
+ super(control);
+
+ // create a map for button-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)
+ buttonInputMap = createInputMap();
+
+ // add focus traversal mappings
+ addDefaultMapping(buttonInputMap, FocusTraversalInputMap.getFocusTraversalMappings());
+
+ // then button-specific mappings for key and mouse input
+ addDefaultMapping(buttonInputMap,
+ new KeyMapping(SPACE, KeyEvent.KEY_PRESSED, this::keyPressed),
+ new KeyMapping(SPACE, KeyEvent.KEY_RELEASED, this::keyReleased),
+ new MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
+ new MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
+ new MouseMapping(MouseEvent.MOUSE_ENTERED, this::mouseEntered),
+ new MouseMapping(MouseEvent.MOUSE_EXITED, this::mouseExited)
+ );
+
+ // Button also cares about focus
+ control.focusedProperty().addListener(this::focusChanged);
}
- public ButtonBehavior(final C button, final List<KeyBinding> bindings) {
- super(button, bindings);
+
+
+ /***************************************************************************
+ * *
+ * Implementation of BehaviorBase API *
+ * *
+ **************************************************************************/
+
+ @Override public InputMap<C> getInputMap() {
+ return buttonInputMap;
}
+ @Override public void dispose() {
+ super.dispose();
+
+ // TODO
+ getNode().focusedProperty().removeListener(this::focusChanged);
+ }
+
+
+
/***************************************************************************
* *
* Focus change handling *
* *
**************************************************************************/
- @Override protected void focusChanged() {
+ private void focusChanged(Observable o) {
// If we did have the key down, but are now not focused, then we must
// disarm the button.
- final ButtonBase button = getControl();
+ final ButtonBase button = getNode();
if (keyDown && !button.isFocused()) {
keyDown = false;
button.disarm();
}
}
+
+
/***************************************************************************
* *
* Key event handling *
* *
**************************************************************************/
/**
- * Indicates that a keyboard key has been pressed which represents the
- * event (this could be space bar for example). As long as keyDown is true,
- * we are also armed, and will ignore mouse events related to arming.
- * Note this is made package private solely for the sake of testing.
- */
- private boolean keyDown;
-
- private static final String PRESS_ACTION = "Press";
- private static final String RELEASE_ACTION = "Release";
-
- protected static final List<KeyBinding> BUTTON_BINDINGS = new ArrayList<KeyBinding>();
- static {
- BUTTON_BINDINGS.add(new KeyBinding(TAB, "TraverseNext"));
- BUTTON_BINDINGS.add(new KeyBinding(TAB, "TraversePrevious").shift());
-
- BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_PRESSED, PRESS_ACTION));
- BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_RELEASED, RELEASE_ACTION));
- }
-
- @Override protected void callAction(String name) {
- if (!getControl().isDisabled()) {
- if (PRESS_ACTION.equals(name)) {
- keyPressed();
- } else if (RELEASE_ACTION.equals(name)) {
- keyReleased();
- } else {
- super.callAction(name);
- }
- }
- }
-
- /**
* This function is invoked when an appropriate keystroke occurs which
* causes this button to be armed if it is not already armed by a mouse
* press.
*/
- private void keyPressed() {
- final ButtonBase button = getControl();
- if (! button.isPressed() && ! button.isArmed()) {
+ protected void keyPressed(KeyEvent e) {
+ if (! getNode().isPressed() && ! getNode().isArmed()) {
keyDown = true;
- button.arm();
+ getNode().arm();
}
}
/**
* Invoked when a valid keystroke release occurs which causes the button
* to fire if it was armed by a keyPress.
*/
- private void keyReleased() {
- final ButtonBase button = getControl();
+ protected void keyReleased(KeyEvent e) {
if (keyDown) {
keyDown = false;
- if (button.isArmed()) {
- button.disarm();
- button.fire();
+ if (getNode().isArmed()) {
+ getNode().disarm();
+ getNode().fire();
}
}
}
+
+
/***************************************************************************
* *
* Mouse event handling *
* *
**************************************************************************/
/**
* Invoked when a mouse press has occurred over the button. In addition to
* potentially arming the Button, this will transfer focus to the button
*/
- @Override public void mousePressed(MouseEvent e) {
- final ButtonBase button = getControl();
- super.mousePressed(e);
+ protected void mousePressed(MouseEvent e) {
// if the button is not already focused, then request the focus
- if (! button.isFocused() && button.isFocusTraversable()) {
- button.requestFocus();
+ if (! getNode().isFocused() && getNode().isFocusTraversable()) {
+ getNode().requestFocus();
}
// arm the button if it is a valid mouse event
// Note there appears to be a bug where if I press and hold and release
// then there is a clickCount of 0 on the release, whereas a quick click
@@ -167,52 +181,47 @@
// though it should really be == 1 I think.
boolean valid = (e.getButton() == MouseButton.PRIMARY &&
! (e.isMiddleButtonDown() || e.isSecondaryButtonDown() ||
e.isShiftDown() || e.isControlDown() || e.isAltDown() || e.isMetaDown()));
- if (! button.isArmed() && valid) {
- button.arm();
+ if (! getNode().isArmed() && valid) {
+ getNode().arm();
}
}
/**
* Invoked when a mouse release has occurred. We determine whether this
* was done in a manner that would fire the button's action. This happens
* only if the button was armed by a corresponding mouse press.
*/
- @Override public void mouseReleased(MouseEvent e) {
+ protected void mouseReleased(MouseEvent e) {
// if armed by a mouse press instead of key press, then fire!
- final ButtonBase button = getControl();
- if (! keyDown && button.isArmed()) {
- button.fire();
- button.disarm();
+ if (! keyDown && getNode().isArmed()) {
+ getNode().fire();
+ getNode().disarm();
}
}
/**
* Invoked when the mouse enters the Button. If the Button had been armed
* by a mouse press and the mouse is still pressed, then this will cause
* the button to be rearmed.
*/
- @Override public void mouseEntered(MouseEvent e) {
+ protected void mouseEntered(MouseEvent e) {
// rearm if necessary
- final ButtonBase button = getControl();
- super.mouseEntered(e);
- if (! keyDown && button.isPressed()) {
- button.arm();
+ if (! keyDown && getNode().isPressed()) {
+ getNode().arm();
}
}
/**
* Invoked when the mouse exits the Button. If the Button is armed due to
* a mouse press, then this function will disarm the button upon the mouse
* exiting it.
*/
- @Override public void mouseExited(MouseEvent e) {
+ protected void mouseExited(MouseEvent e) {
// Disarm if necessary
- final ButtonBase button = getControl();
- super.mouseExited(e);
- if (! keyDown && button.isArmed()) {
- button.disarm();
+ if (! keyDown && getNode().isArmed()) {
+ getNode().disarm();
}
}
}