001: package abbot.editor.recorder;
002:
003: import java.awt.AWTEvent;
004: import java.awt.event.KeyEvent;
005:
006: import javax.swing.*;
007:
008: import abbot.Log;
009: import abbot.script.*;
010:
011: /**
012: * Record basic semantic events you might find on an JComponent. <p>
013: *
014: * Watches for events that trigger an action from the component's action map.
015: * As of 1.3.1, KEY_TYPED and KEY_RELEASED events can trigger an action.
016: */
017: public class JComponentRecorder extends ContainerRecorder {
018:
019: private JComponent target;
020: private String actionKey;
021:
022: public static final int SE_ACTION_MAP = 20;
023:
024: public JComponentRecorder(Resolver resolver) {
025: super (resolver);
026: }
027:
028: protected void init(int rtype) {
029: super .init(rtype);
030: target = null;
031: actionKey = null;
032: }
033:
034: /** Add handling for JComponent input-mapped actions. */
035: public boolean accept(AWTEvent event) {
036: boolean accepted;
037: if ((event instanceof KeyEvent)
038: && (event.getSource() instanceof JComponent)
039: && isMappedEvent((KeyEvent) event)) {
040: init(SE_ACTION_MAP);
041: accepted = true;
042: } else {
043: accepted = super .accept(event);
044: }
045: return accepted;
046: }
047:
048: protected javax.swing.Action getAction(KeyEvent ke) {
049: KeyStroke ks = KeyStroke.getKeyStrokeForEvent(ke);
050: JComponent comp = (JComponent) ke.getComponent();
051: Object binding = comp.getInputMap().get(ks);
052: return binding != null ? comp.getActionMap().get(binding)
053: : null;
054: }
055:
056: protected boolean isMappedEvent(KeyEvent ke) {
057: return getAction(ke) != null;
058: }
059:
060: /** Add handling for JComponent input-mapped actions. */
061: public boolean parse(AWTEvent event) {
062: boolean consumed = true;
063: switch (getRecordingType()) {
064: case SE_ACTION_MAP:
065: consumed = parseActionMapEvent(event);
066: break;
067: default:
068: consumed = super .parse(event);
069: break;
070: }
071: return consumed;
072: }
073:
074: /** Add handling for JComponent input-mapped actions. */
075: protected boolean parseActionMapEvent(AWTEvent event) {
076: if (target == null) {
077: target = (JComponent) event.getSource();
078: KeyStroke ks = KeyStroke
079: .getKeyStrokeForEvent((KeyEvent) event);
080: Object binding = target.getInputMap().get(ks);
081: Log.debug("Binding is " + binding + " ("
082: + binding.getClass() + ")");
083: if (binding instanceof String) {
084: actionKey = (String) binding;
085: } else {
086: // 1.3 and prior sometimes used the actions themselves
087: // as the key
088: javax.swing.Action action = target.getActionMap().get(
089: binding);
090: actionKey = (String) action
091: .getValue(javax.swing.Action.NAME);
092: }
093: Log.debug("Keystroke '" + ks + "' mapped to " + actionKey);
094: }
095: // Make sure the entire KEY_PRESSED/KEY_TYPED/KEY_RELEASED
096: // sequence is eaten
097: // NOTE: This assumes that no component expects to respond to both the
098: // key shortcut AND accept the key input.
099: if (event.getID() == KeyEvent.KEY_RELEASED) {
100: setFinished(true);
101: }
102: return true;
103: }
104:
105: /** Add handling for JComponent input-mapped actions. */
106: protected Step createStep() {
107: Step step;
108: switch (getRecordingType()) {
109: case SE_ACTION_MAP:
110: step = createActionMap(target, actionKey);
111: break;
112: default:
113: step = super .createStep();
114: break;
115: }
116: return step;
117: }
118:
119: /** Create a JComponent input-mapped action invocation. */
120: protected Step createActionMap(JComponent target, String actionKey) {
121: ComponentReference cr = getResolver().addComponent(target);
122: return new abbot.script.Action(getResolver(), null,
123: "actionActionMap",
124: new String[] { cr.getID(), actionKey },
125: JComponent.class);
126: }
127: }
|