package jetbrains.mps.lang.test.runtime;
/*Generated by MPS */
import java.lang.reflect.InvocationTargetException;
import java.awt.event.KeyEvent;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.internal.collections.runtime.ArrayUtils;
import jetbrains.mps.internal.collections.runtime.ISelector;
import java.util.List;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.internal.collections.runtime.ITranslator2;
import java.util.Iterator;
import jetbrains.mps.baseLanguage.closures.runtime.YieldingIterator;
import javax.swing.KeyStroke;
import java.awt.Component;
import java.lang.reflect.Method;
import jetbrains.mps.internal.collections.runtime.IVisitor;
import junit.framework.Assert;
import jetbrains.mps.nodeEditor.EditorComponent;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import javax.swing.JComponent;
public class KeyEventsDispatcher {
private final BaseEditorTestBody myEditorTest;
public KeyEventsDispatcher(BaseEditorTestBody editorTest) {
myEditorTest = editorTest;
}
public void typeString(final String text) throws InterruptedException, InvocationTargetException {
Iterable<KeyEvent> events = Sequence.fromIterable(ArrayUtils.fromCharacterArray(text.toCharArray())).select(new ISelector<Character, KeyEvent>() {
public KeyEvent select(Character it) {
return new KeyEvent(myEditorTest.getEditorComponent(), KeyEvent.KEY_TYPED, 0, 0, 0, it);
}
});
processKeyEvents(events);
}
public void pressKeys(final List<String> keyStrokes) throws InterruptedException, InvocationTargetException {
Iterable<KeyEvent> events = ListSequence.fromList(keyStrokes).translate(new ITranslator2<String, KeyEvent>() {
public Iterable<KeyEvent> translate(final String it) {
return new Iterable<KeyEvent>() {
public Iterator<KeyEvent> iterator() {
return new YieldingIterator<KeyEvent>() {
private int __CP__ = 0;
protected boolean moveToNext() {
__loop__:
do {
__switch__:
switch (this.__CP__) {
case -1:
assert false : "Internal error";
return false;
case 6:
if (_5_keyChar == KeyEvent.CHAR_UNDEFINED && _4_keyCode != KeyEvent.VK_UNDEFINED && ((_4_keyCode >= KeyEvent.VK_0 && _4_keyCode <= KeyEvent.VK_9) || (_4_keyCode >= KeyEvent.VK_A && _4_keyCode <= KeyEvent.VK_Z))) {
this.__CP__ = 7;
break;
}
this.__CP__ = 8;
break;
case 8:
this.__CP__ = 10;
this.yield(new KeyEvent(myEditorTest.getEditorComponent(), KeyEvent.KEY_PRESSED, 0, _3_stroke.getModifiers(), _4_keyCode, _5_keyChar));
return true;
case 10:
this.__CP__ = 1;
this.yield(new KeyEvent(myEditorTest.getEditorComponent(), KeyEvent.KEY_RELEASED, 0, _3_stroke.getModifiers(), _4_keyCode, _5_keyChar));
return true;
case 0:
this._3_stroke = KeyStroke.getKeyStroke(it);
this._4_keyCode = _3_stroke.getKeyCode();
this._5_keyChar = _3_stroke.getKeyChar();
this.__CP__ = 6;
break;
case 7:
// todo it may be worthwhile to also detect other unicode chars from keyCode and supply them into keyChar
// There is currently no good complete cross-platform code to char conversion utility, it seems
// KEY_PRESSED events may or may not contain a concrete keyChar. Its presence is definitely not a problem
_5_keyChar = (char) _4_keyCode;
this.__CP__ = 8;
break;
default:
break __loop__;
}
} while (true);
return false;
}
private KeyStroke _3_stroke;
private int _4_keyCode;
private char _5_keyChar;
};
}
};
}
});
processKeyEvents(events);
}
private void processKeyEvents(final Iterable<KeyEvent> events) throws InterruptedException, InvocationTargetException {
final Component eventTargetComponent = getKeyEventTargetComponent();
final Method processKeyEventMethod = KeyEventsDispatcher.getProcessKeyEventMethod(eventTargetComponent);
final boolean[] eventsPassed = new boolean[]{true};
if (eventTargetComponent == null) {
myEditorTest.runUndoableInEDTAndWait(new Runnable() {
public void run() {
Sequence.fromIterable(events).visitAll(new IVisitor<KeyEvent>() {
public void visit(KeyEvent it) {
if (it.getID() == KeyEvent.KEY_TYPED) {
myEditorTest.getEditorComponent().processKeyTyped(it);
} else if (it.getID() == KeyEvent.KEY_PRESSED) {
myEditorTest.getEditorComponent().processKeyPressed(it);
} else if (it.getID() == KeyEvent.KEY_RELEASED) {
myEditorTest.getEditorComponent().processKeyReleased(it);
} else {
assert false : "Wrong Id " + it.getID();
}
}
});
}
});
} else {
myEditorTest.runUndoableInEDTAndWait(new Runnable() {
public void run() {
for (KeyEvent event : Sequence.fromIterable(events)) {
try {
processKeyEventMethod.invoke(eventTargetComponent, event);
} catch (InvocationTargetException e) {
eventsPassed[0] = false;
} catch (IllegalAccessException e) {
eventsPassed[0] = false;
}
}
}
});
}
Assert.assertTrue("Keyboard events were not passed to corresponding component", eventsPassed[0]);
}
private Component getKeyEventTargetComponent() {
EditorComponent editorComponent = myEditorTest.getEditorComponent();
EditorCell selectedCell = editorComponent.getSelectedCell();
if (selectedCell == null) {
// TODO: return editorComponent here
return null;
}
Component eventTarget = EditorUtil.getEventTargetComponent(selectedCell, editorComponent);
if (eventTarget == editorComponent) {
// TODO: return editorComponent here
return null;
}
while ((eventTarget instanceof JComponent) && ((JComponent) eventTarget).getComponentCount() > 0) {
eventTarget = ((JComponent) eventTarget).getComponent(((JComponent) eventTarget).getComponentCount() - 1);
}
return eventTarget;
}
private static Method getProcessKeyEventMethod(Component eventTargetComponent) {
if (eventTargetComponent == null) {
return null;
}
Class<?> clazz = eventTargetComponent.getClass();
Method theMethod = null;
while (theMethod == null && clazz != null) {
try {
theMethod = clazz.getDeclaredMethod("processKeyEvent", KeyEvent.class);
theMethod.setAccessible(true);
return theMethod;
} catch (NoSuchMethodException e) {
}
clazz = clazz.getSuperclass();
}
Assert.fail("Cannot find processKeyEvent method in " + eventTargetComponent.getClass() + "class");
return null;
}
}