org.jdesktop.swingx.event.KeyBindingDispatcher Maven / Gradle / Ivy
/*
* Created on 22.03.2013
*
*/
package org.jdesktop.swingx.event;
import java.awt.KeyEventDispatcher;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.KeyStroke;
import org.jdesktop.swingx.util.Contract;
/**
* KeyEventDispatcher for application-wide KeyBindings.
*
*
* The mechanism is the same as for component bindings, that is using a pair
* InputMap/ActionMap
. The maps can be accessed directly to bind
* KeyStrokes and Actions individually. Additionally, the implementation provides
* convenience methods
* to bind pairs of KeyStroke/Action
easily.
* Once the dispatcher is added to the KeyboardFocusManager, all KeyEvents will
* be served first to the bindings (modulo other dispatchers earlier in the chain),
* and consumed if an action is available, enabled and performed.
*
*
* Usage:
*
*
* KeyBindingDispatcher d = new KeyBindingDispatcher();
* d.bind(myKeyStroke, myAction);
* KeyboardFocusManager.getCurrentKeyboardFocusManager()
* .addKeyEventDispatcher(d);
*
*
*
* @author Jeanette Winzenburg, Berlin
*/
public class KeyBindingDispatcher implements KeyEventDispatcher {
private InputMap inputMap;
private ActionMap actionMap;
/**
* Implemented to process the key binding for the event. If a binding is
* available, the bound action is performed and the event is consumed. Does
* nothing if the event already is consumed. The returned value is false
* always to allow other dispatchers to handle the event as well
*
*
* Subclasses may re-implement to return true and end the dispatch here.
*
*
* @param e the keyEvent to dispatch
* @return unconditionally false
*/
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (!e.isConsumed()) {
if (processKeyBinding(e)) {
e.consume();
}
}
return false;
}
/**
* Processes the keyBinding for the keyEvent and returns a boolean
* indicating whether a bound action was performed.
*
* @param e the KeyEvent to handle
* @return true if a bound action was available, enabled and performed,
* false otherwise
*/
protected boolean processKeyBinding(KeyEvent e) {
Action action = getAction(e);
if (action != null && action.isEnabled()) {
ActionEvent actionEvent = createActionEvent(e, action);
action.actionPerformed(actionEvent);
return true;
}
return false;
}
/**
* Returns the Action bound to the KeyStroke that corresponds to the
* keyEvent, or null if none available.
*
* @param e the keyEvent to find a binding for
* @return the action bound to the keyStroke that corresponds to the
* keyEvent or null if not available
*/
protected Action getAction(KeyEvent e) {
KeyStroke stroke = KeyStroke.getKeyStrokeForEvent(e);
Object actionKey = getInputMap().get(stroke);
if (actionKey != null) {
return getActionMap().get(actionKey);
}
return null;
}
/**
* Creates and returns an ActionEvent that can be passed into the action's
* actionPerformed. Similar configuration as SwingUtilities.notifyAction,
* except ignoring standIn actions.
*
* @param e the KeyEvent bound to the action
* @param action the bound action
* @return the actionEvent that will be passed into the action's
* actionPerformed.
*
* @see javax.swing.SwingUtilities#notifyAction(Action, KeyStroke, KeyEvent,
* Object, int)
*/
protected ActionEvent createActionEvent(KeyEvent e, Action action) {
Object command0 = action.getValue(Action.ACTION_COMMAND_KEY);
String command = null;
if (command0 != null) {
command = command0.toString();
} else if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
command = String.valueOf(e.getKeyChar());
}
ActionEvent actionEvent = new ActionEvent(e.getSource(),
ActionEvent.ACTION_PERFORMED, command, e.getWhen(),
e.getModifiers());
return actionEvent;
}
/**
* Binds the keyStroke and action, using the given key which must not be
* null.
*
*
* @param keyStroke the keyStroke to bind
* @param action the action to bind.
* @param key the key used for binding, must not be null.
*/
public void bind(KeyStroke keyStroke, Action action, Object key) {
Contract.asNotNull(key, "binding key must not be null");
put(keyStroke, key);
put(key, action);
}
/**
* Returns the ActionMap used for key bindings, lazily created if not yet
* done.
*
* @return the ActionMap used for key bindings
*/
public ActionMap getActionMap() {
if (actionMap == null) {
actionMap = new ActionMap();
}
return actionMap;
}
/**
* Returns the InputMap used for key bindings, lazily created if not yet
* done.
*
* @return the InputMap used for key bindings.
*/
public InputMap getInputMap() {
if (inputMap == null) {
inputMap = new InputMap();
}
return inputMap;
}
/**
* Binds the keyStroke and action, a key is auto-created.
*
* @param keyStroke the keyStroke to bind
* @param action the action to bind.
*/
public void bind(KeyStroke keyStroke, Action action) {
bind(keyStroke, action, createAutoKey());
}
/**
* Creates and returns a unique actionMapKey.
*
* @return a unique key used for binding in input/actionMap.
*/
protected Object createAutoKey() {
long millis = System.currentTimeMillis();
String key = "auto" + millis;
while (get(key) != null) {
key = "auto" + millis--;
}
return key;
}
/**
* Registers a binding for keyStroke
to
* actionMapKey
. Semantics are the same as the corresponding
* method in InputMap.
*
* @param keyStroke the keyStroke to bind
* @param key the key used for binding.
*
* @see javax.swing.InputMap#put(KeyStroke, Object)
*/
public void put(KeyStroke keyStroke, Object actionMapKey) {
getInputMap().put(keyStroke, actionMapKey);
}
/**
* Returns the actionMapKey registerd for the keyStroke.
*
* @param keyStroke the keyStroke to bind
* @return the actionMapKey for the keyStroke or null if unbound.
*/
public Object get(KeyStroke keyStroke) {
return getInputMap().get(keyStroke);
}
/**
* Registers a binding for key
to action
.
* Semantics are the same as that of the corresponding method in ActionMap.
*
* @param key the key used for binding.
* @param action the action to bind.
*
* @see javax.swing.ActionMap#put(Object, Action)
*/
public void put(Object key, Action action) {
getActionMap().put(key, action);
}
/**
* Returns the Action registered for key or null if none.
*
* @param key the key used for binding.
* @return the action registered for key or null it none available.
*/
public Action get(Object key) {
return getActionMap().get(key);
}
}