/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.swing.recorder; import java.awt.AWTEvent; import java.awt.event.KeyEvent; import javax.swing.JComponent; import javax.swing.KeyStroke; import abbot.Log; import abbot.script.ComponentReference; import abbot.script.Resolver; import abbot.script.Step; import com.windowtester.recorder.event.IUISemanticEvent; import com.windowtester.recorder.event.UISemanticEventFactory; /** * Record basic semantic events you might find on an JComponent. <p> * * Watches for events that trigger an action from the component's action map. * As of 1.3.1, KEY_TYPED and KEY_RELEASED events can trigger an action. * * added generation of windowtester semantic event */ public class JComponentRecorder extends ContainerRecorder { private JComponent target; private String actionKey; // keystroke used to generate semantic event private KeyStroke ks; int code; char ch; public static final int SE_ACTION_MAP = 20; public JComponentRecorder(Resolver resolver) { super(resolver); } protected void init(int rtype) { super.init(rtype); target = null; actionKey = null; } /** Add handling for JComponent input-mapped actions. */ public boolean accept(AWTEvent event) { boolean accepted; if ((event instanceof KeyEvent) && (event.getSource() instanceof JComponent) && isMappedEvent((KeyEvent)event)) { init(SE_ACTION_MAP); accepted = true; } else { accepted = super.accept(event); } return accepted; } protected javax.swing.Action getAction(KeyEvent ke) { KeyStroke ks = KeyStroke.getKeyStrokeForEvent(ke); JComponent comp = (JComponent)ke.getComponent(); Object binding = comp.getInputMap().get(ks); return binding != null ? comp.getActionMap().get(binding) : null; } protected boolean isMappedEvent(KeyEvent ke) { return getAction(ke) != null; } /** Add handling for JComponent input-mapped actions. */ public boolean parse(AWTEvent event) { boolean consumed = true; switch(getRecordingType()) { case SE_ACTION_MAP: consumed = parseActionMapEvent(event); break; default: consumed = super.parse(event); break; } return consumed; } /** Add handling for JComponent input-mapped actions. */ protected boolean parseActionMapEvent(AWTEvent event) { if (target == null) { target = (JComponent)event.getSource(); KeyStroke ks = KeyStroke.getKeyStrokeForEvent((KeyEvent)event); ch = ((KeyEvent)event).getKeyChar(); code = ((KeyEvent)event).getKeyCode(); Object binding = target.getInputMap().get(ks); Log.debug("Binding is " + binding + " (" + binding.getClass() + ")"); if (binding instanceof String) { actionKey = (String)binding; } else { // 1.3 and prior sometimes used the actions themselves // as the key javax.swing.Action action = target.getActionMap().get(binding); actionKey = (String)action.getValue(javax.swing.Action.NAME); } Log.debug("Keystroke '" + ks + "' mapped to " + actionKey); } // Make sure the entire KEY_PRESSED/KEY_TYPED/KEY_RELEASED // sequence is eaten // NOTE: This assumes that no component expects to respond to both the // key shortcut AND accept the key input. if (event.getID() == KeyEvent.KEY_RELEASED) { setFinished(true); } return true; } /** Add handling for JComponent input-mapped actions. */ protected Step createStep() { Step step; switch(getRecordingType()) { case SE_ACTION_MAP: step = createActionMap(target, actionKey); break; default: step = super.createStep(); break; } return step; } /** Create a JComponent input-mapped action invocation. */ protected Step createActionMap(JComponent target, String actionKey) { // generate semantic event IUISemanticEvent semanticEvent = UISemanticEventFactory.createKeyDownEvent(target,code,ch); notify(semanticEvent); ComponentReference cr = getResolver().addComponent(target); return new abbot.script.Action(getResolver(), null, "actionActionMap", new String[] { cr.getID(), actionKey }, JComponent.class); } }