macro playback fixed

This commit is contained in:
Kirill Kalishev
2009-11-13 20:17:22 +03:00
parent e5ae2bb41c
commit 05bcac51cc
16 changed files with 109 additions and 40 deletions
@@ -439,7 +439,7 @@ public class PlaybackDebugger implements UiDebuggerExtension, PlaybackRunner.Sta
myMessage.clear();
addInfo("Waiting for IDE frame activation", -1);
myRunner = new PlaybackRunner(myDocument.getText(), this);
myRunner = new PlaybackRunner(myDocument.getText(), this, false);
new Thread() {
@@ -29,6 +29,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher;
import com.intellij.openapi.keymap.impl.IdeMouseEventDispatcher;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
@@ -48,10 +49,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
@@ -83,7 +81,7 @@ public class IdeEventQueue extends EventQueue {
private final Map<Runnable, MyFireIdleRequest> myListener2Request = new HashMap<Runnable, MyFireIdleRequest>();
// IdleListener -> MyFireIdleRequest
private final IdeKeyEventDispatcher myKeyEventDispatcher = new IdeKeyEventDispatcher();
private final IdeKeyEventDispatcher myKeyEventDispatcher = new IdeKeyEventDispatcher(this);
private final IdeMouseEventDispatcher myMouseEventDispatcher = new IdeMouseEventDispatcher();
@@ -130,6 +128,9 @@ public class IdeEventQueue extends EventQueue {
private final Set<EventDispatcher> myDispatchers = new LinkedHashSet<EventDispatcher>();
private final Set<EventDispatcher> myPostprocessors = new LinkedHashSet<EventDispatcher>();
private Set<Runnable> myReady = new HashSet<Runnable>();
private boolean myKeyboardBusy;
private static class IdeEventQueueHolder {
private static final IdeEventQueue INSTANCE = new IdeEventQueue();
}
@@ -379,6 +380,10 @@ public class IdeEventQueue extends EventQueue {
each.dispatch(e);
}
if (e instanceof KeyEvent) {
maybeReady();
}
if (DEBUG) {
final long processTime = System.currentTimeMillis() - t;
if (processTime > 100) {
@@ -427,6 +432,10 @@ public class IdeEventQueue extends EventQueue {
enterSuspendModeIfNeeded(e);
}
if (e instanceof KeyEvent) {
myKeyboardBusy = e.getID() != KeyEvent.KEY_RELEASED || ((KeyEvent)e).getModifiers() != 0;
}
if (typeAheadDispatchToFocusManager(e)) return;
if (e instanceof WindowEvent) {
@@ -735,4 +744,37 @@ public class IdeEventQueue extends EventQueue {
public boolean hasFocusEventsPending() {
return peekEvent(FocusEvent.FOCUS_GAINED) != null || peekEvent(FocusEvent.FOCUS_LOST) != null;
}
private boolean isReady() {
return !myKeyboardBusy && myKeyEventDispatcher.isReady();
}
public void maybeReady() {
flushReady();
}
private void flushReady() {
if (myReady.size() == 0 || !isReady()) return;
Runnable[] ready = myReady.toArray(new Runnable[myReady.size()]);
myReady.clear();
for (Runnable each : ready) {
each.run();
}
}
public void doWhenReady(final Runnable runnable) {
if (EventQueue.isDispatchThread()) {
myReady.add(runnable);
maybeReady();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myReady.add(runnable);
maybeReady();
}
});
}
}
}
@@ -30,6 +30,7 @@ import com.intellij.openapi.ui.playback.PlaybackRunner;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.NamedJDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import org.jdom.Element;
@@ -212,7 +213,7 @@ public class ActionMacroManager implements ExportableApplicationComponent, Named
public void messageEdt(String text, int curentLine) {
frame.getStatusBar().setInfo("Line " + curentLine + ": " + text);
}
});
}, Registry.is("actionSystem.playback.useDirectActionCall"));
myIsPlaying = true;
@@ -93,8 +93,10 @@ public final class IdeKeyEventDispatcher implements Disposable {
private final KeyboardGestureProcessor myKeyGestureProcessor = new KeyboardGestureProcessor(this);
private final KeyProcessorContext myContext = new KeyProcessorContext();
private IdeEventQueue myQueue;
public IdeKeyEventDispatcher(){
public IdeKeyEventDispatcher(IdeEventQueue queue){
myQueue = queue;
Application parent = ApplicationManager.getApplication(); // Application is null on early start when e.g. license dialog is shown
if (parent != null) Disposer.register(parent, this);
}
@@ -348,7 +350,9 @@ public final class IdeKeyEventDispatcher implements Disposable {
KeyStroke originalKeyStroke=KeyStroke.getKeyStrokeForEvent(e);
KeyStroke keyStroke=getKeyStrokeWithoutMouseModifiers(originalKeyStroke);
if (myKeyGestureProcessor.processInitState()) return true;
if (myKeyGestureProcessor.processInitState()) {
return true;
}
if (SystemInfo.isMac) {
if (e.getModifiersEx() == InputEvent.ALT_DOWN_MASK &&
@@ -620,6 +624,9 @@ public final class IdeKeyEventDispatcher implements Disposable {
public void setState(final int state) {
myState = state;
if (myQueue != null) {
myQueue.maybeReady();
}
}
public void resetState() {
@@ -634,4 +641,8 @@ public final class IdeKeyEventDispatcher implements Disposable {
public void setPressedWasProcessed(boolean pressedWasProcessed) {
myPressedWasProcessed = pressedWasProcessed;
}
public boolean isReady() {
return myState == STATE_INIT;
}
}
@@ -20,6 +20,6 @@ import com.intellij.openapi.util.ActionCallback;
import java.awt.*;
public interface PlaybackCommand {
ActionCallback execute(PlaybackRunner.StatusCallback cb, Robot robot);
ActionCallback execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean useDirectActionCall);
boolean canGoFurther();
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.ui.playback;
import com.intellij.ide.IdeEventQueue;
import com.intellij.openapi.ui.playback.commands.AssertFocused;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.playback.commands.*;
@@ -39,10 +40,12 @@ public class PlaybackRunner {
private ArrayList<PlaybackCommand> myCommands = new ArrayList<PlaybackCommand>();
private ActionCallback myActionCallback;
private boolean myStopRequested;
private boolean myUseDirectActionCall;
public PlaybackRunner(String script, StatusCallback callback) {
public PlaybackRunner(String script, StatusCallback callback, final boolean useDirectActionCall) {
myScript = script;
myCallback = callback;
myUseDirectActionCall = useDirectActionCall;
}
public ActionCallback run() {
@@ -58,7 +61,15 @@ public class PlaybackRunner {
new Thread() {
@Override
public void run() {
executeFrom(0);
if (myUseDirectActionCall) {
executeFrom(0);
} else {
IdeEventQueue.getInstance().doWhenReady(new Runnable() {
public void run() {
executeFrom(0);
}
});
}
}
}.start();
@@ -78,7 +89,7 @@ public class PlaybackRunner {
myActionCallback.setRejected();
return;
}
cmd.execute(myCallback, myRobot).doWhenDone(new Runnable() {
cmd.execute(myCallback, myRobot, myUseDirectActionCall).doWhenDone(new Runnable() {
public void run() {
if (cmd.canGoFurther()) {
executeFrom(cmdIndex + 1);
@@ -226,7 +237,7 @@ public class PlaybackRunner {
public void message(String text, int currentLine) {
System.out.println(currentLine + " " + text);
}
}).run();
}, false).run();
}
@@ -45,10 +45,10 @@ public abstract class AbstractCommand implements PlaybackCommand {
return true;
}
public final ActionCallback execute(PlaybackRunner.StatusCallback cb, Robot robot) {
public final ActionCallback execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean useDirectActionCall) {
try {
dumpCommand(cb);
return _execute(cb, robot);
return _execute(cb, robot, useDirectActionCall);
}
catch (Exception e) {
cb.error(e.getMessage(), getLine());
@@ -56,7 +56,7 @@ public abstract class AbstractCommand implements PlaybackCommand {
}
}
protected abstract ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot);
protected abstract ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall);
public void dumpCommand(final PlaybackRunner.StatusCallback cb) {
cb.message(getText(), getLine());
@@ -38,7 +38,7 @@ public class ActionCommand extends TypeCommand {
super(text, line);
}
protected ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
protected ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
final String actionName = getText().substring(PREFIX.length()).trim();
final AnAction action = ActionManager.getInstance().getAction(actionName);
@@ -48,23 +48,26 @@ public class ActionCommand extends TypeCommand {
}
final Shortcut[] sc = KeymapManager.getInstance().getActiveKeymap().getShortcuts(actionName);
KeyStroke stroke = null;
for (Shortcut each : sc) {
if (each instanceof KeyboardShortcut) {
final KeyboardShortcut ks = (KeyboardShortcut)each;
final KeyStroke first = ks.getFirstKeyStroke();
final KeyStroke second = ks.getSecondKeyStroke();
if (first != null && second == null) {
stroke = KeyStroke.getKeyStroke(first.getKeyCode(), first.getModifiers(), false);
if (!directActionCall) {
final Shortcut[] sc = KeymapManager.getInstance().getActiveKeymap().getShortcuts(actionName);
KeyStroke stroke = null;
for (Shortcut each : sc) {
if (each instanceof KeyboardShortcut) {
final KeyboardShortcut ks = (KeyboardShortcut)each;
final KeyStroke first = ks.getFirstKeyStroke();
final KeyStroke second = ks.getSecondKeyStroke();
if (first != null && second == null) {
stroke = KeyStroke.getKeyStroke(first.getKeyCode(), first.getModifiers(), false);
break;
}
}
}
}
if (stroke != null) {
cb.message("Invoking action via shortcut: " + stroke.toString(), getLine());
type(robot, stroke);
return new ActionCallback.Done();
if (stroke != null) {
cb.message("Invoking action via shortcut: " + stroke.toString(), getLine());
type(robot, stroke);
return new ActionCallback.Done();
}
}
final InputEvent input = getInputEvent(actionName);
@@ -27,7 +27,7 @@ public class AlphaNumericTypeCommand extends TypeCommand {
super(text, line);
}
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
final String text = getText();
for (int i = 0; i < text.length(); i++) {
final char each = text.charAt(i);
@@ -31,7 +31,7 @@ public class AssertFocused extends AbstractCommand {
super(text, line);
}
protected ActionCallback _execute(final PlaybackRunner.StatusCallback cb, Robot robot) {
protected ActionCallback _execute(final PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
final ActionCallback result = new ActionCallback();
String text = getText().substring(PREFIX.length()).trim();
@@ -27,7 +27,7 @@ public class DelayCommand extends AbstractCommand {
super(text, line);
}
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
final String s = getText().substring(PREFIX.length()).trim();
try {
@@ -25,7 +25,7 @@ public class EmptyCommand extends AbstractCommand {
super("", line);
}
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
return new ActionCallback.Done();
}
}
@@ -26,7 +26,7 @@ public class ErrorCommand extends AbstractCommand {
super(text, line);
}
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
dumpError(cb, getText());
return new ActionCallback.Rejected();
}
@@ -29,7 +29,7 @@ public class KeyShortcutCommand extends TypeCommand {
super(text, line);
}
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
public ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
final String one = getText().substring(PREFIX.length());
if (!one.endsWith("]")) {
dumpError(cb, "Expected " + "]");
@@ -28,7 +28,7 @@ public class StopCommand extends AbstractCommand {
super(text, line);
}
protected ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot) {
protected ActionCallback _execute(PlaybackRunner.StatusCallback cb, Robot robot, boolean directActionCall) {
cb.message("Stopped", getLine());
return new ActionCallback.Done();
}
@@ -15,7 +15,8 @@ actionSystem.commandProcessingTimeout.description=Timeout after which currently
actionSystem.typeAheadTimeBeforeDialog=2000
actionSystem.typeAheadTimeBeforeDialog.description=If dialog shown as a result of some typing, all key types withing this time will be redispatched after dialog is closed
actionSystem.playback.autodelay=20
actionSystem.playback.description=Delay between events generated by the playback runner
actionSystem.playback.autodelay.description=Delay between events generated by the playback runner
actionSystem.playback.useDirectActionCall=true
actionSystem.focusIdleTimeout=20
actionSystem.mac.screenMenuNotUpdatedFix=false
actionSystem.keyGestures.enabled=false