blob: 42f6bd33f39a8ee92ebaab9d52ca2777067ab659 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.tesla.recording.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.rcptt.tesla.core.TeslaFeatures;
import org.eclipse.rcptt.tesla.core.TeslaScenarioContainer;
import org.eclipse.rcptt.tesla.core.protocol.ApplyCellEditor;
import org.eclipse.rcptt.tesla.core.protocol.CheckItem;
import org.eclipse.rcptt.tesla.core.protocol.Children;
import org.eclipse.rcptt.tesla.core.protocol.Click;
import org.eclipse.rcptt.tesla.core.protocol.ClickText;
import org.eclipse.rcptt.tesla.core.protocol.Close;
import org.eclipse.rcptt.tesla.core.protocol.DoubleClick;
import org.eclipse.rcptt.tesla.core.protocol.DragCommand;
import org.eclipse.rcptt.tesla.core.protocol.DragKind;
import org.eclipse.rcptt.tesla.core.protocol.ElementCommand;
import org.eclipse.rcptt.tesla.core.protocol.ElementKind;
import org.eclipse.rcptt.tesla.core.protocol.GetState;
import org.eclipse.rcptt.tesla.core.protocol.GetStateResponse;
import org.eclipse.rcptt.tesla.core.protocol.HoverAtText;
import org.eclipse.rcptt.tesla.core.protocol.HoverAtTextOffset;
import org.eclipse.rcptt.tesla.core.protocol.Parent;
import org.eclipse.rcptt.tesla.core.protocol.ProtocolFactory;
import org.eclipse.rcptt.tesla.core.protocol.RapUploadFile;
import org.eclipse.rcptt.tesla.core.protocol.SelectCommand;
import org.eclipse.rcptt.tesla.core.protocol.SelectResponse;
import org.eclipse.rcptt.tesla.core.protocol.SetCaretPosition;
import org.eclipse.rcptt.tesla.core.protocol.SetCursorOffset;
import org.eclipse.rcptt.tesla.core.protocol.SetFocus;
import org.eclipse.rcptt.tesla.core.protocol.SetSWTDialogInfo;
import org.eclipse.rcptt.tesla.core.protocol.SetSelection;
import org.eclipse.rcptt.tesla.core.protocol.SetStatusDialogMode;
import org.eclipse.rcptt.tesla.core.protocol.SetText;
import org.eclipse.rcptt.tesla.core.protocol.SetTextOffset;
import org.eclipse.rcptt.tesla.core.protocol.SetTextSelection;
import org.eclipse.rcptt.tesla.core.protocol.SetTextSelection2;
import org.eclipse.rcptt.tesla.core.protocol.Type;
import org.eclipse.rcptt.tesla.core.protocol.TypeText;
import org.eclipse.rcptt.tesla.core.protocol.UIPlayer;
import org.eclipse.rcptt.tesla.core.protocol.UpdateControlCommand;
import org.eclipse.rcptt.tesla.core.protocol.WaitForRestart;
import org.eclipse.rcptt.tesla.core.protocol.WaitForState;
import org.eclipse.rcptt.tesla.core.protocol.diagram.ActivateDirectEdit;
import org.eclipse.rcptt.tesla.core.protocol.diagram.CreateFigure;
import org.eclipse.rcptt.tesla.core.protocol.diagram.FigureMouseCommand;
import org.eclipse.rcptt.tesla.core.protocol.diagram.MouseCommand;
import org.eclipse.rcptt.tesla.core.protocol.diagram.MouseCommandKind;
import org.eclipse.rcptt.tesla.core.protocol.raw.Command;
import org.eclipse.rcptt.tesla.core.protocol.raw.CommandTransferKind;
import org.eclipse.rcptt.tesla.core.protocol.raw.Element;
import org.eclipse.rcptt.tesla.core.protocol.raw.RawEvent;
import org.eclipse.rcptt.tesla.core.protocol.raw.Response;
import org.eclipse.rcptt.tesla.core.ui.Widget;
import org.eclipse.rcptt.tesla.internal.core.processing.ElementGenerator;
public class BaseTeslaRecorder extends UIPlayer {
private ElementGenerator generator = new ElementGenerator();
private final TeslaScenarioContainer container = new TeslaScenarioContainer();
private List<Widget> controls;
private final List<RawEvent> rawEvents = new ArrayList<RawEvent>();
private static boolean rawEventsEnabled;
private static boolean notNativeEventsIgnored;
private String[] recordModeShortcuts;
private String[] assertModeShortcuts;
private String[] startRecordShortcuts;
private String[] stopRecordShortcuts;
private String[] replayShortcuts;
private int replaceIndex = 0;
private boolean skipNext = false;
public BaseTeslaRecorder() {
}
public synchronized void addRawEvent(RawEvent event) {
if (rawEventsEnabled) {
rawEvents.add(event);
}
}
public boolean isRawEventsEnabled() {
synchronized (BaseTeslaRecorder.class) {
return rawEventsEnabled;
}
}
public void setRawEvents(boolean equals) {
synchronized (BaseTeslaRecorder.class) {
rawEventsEnabled = equals;
}
}
public boolean isNotNativeEventsIgnored() {
synchronized (BaseTeslaRecorder.class) {
return notNativeEventsIgnored;
}
}
public void setNotNativeEventsIgnored(boolean value) {
synchronized (BaseTeslaRecorder.class) {
notNativeEventsIgnored = value;
}
}
public synchronized String[] getRecordModeShortcuts() {
return recordModeShortcuts;
}
public synchronized String[] getAssertModeShortcuts() {
return assertModeShortcuts;
}
public synchronized String[] getStartRecordShortcuts() {
return startRecordShortcuts;
}
public synchronized String[] getStopRecordShortcuts() {
return stopRecordShortcuts;
}
public synchronized String[] getReplayShortcuts() {
return replayShortcuts;
}
public synchronized void setRecordModeShortcuts(String[] recordModeShortcuts) {
this.recordModeShortcuts = recordModeShortcuts;
}
public synchronized void setAssertModeShortcuts(String[] shortcuts) {
this.assertModeShortcuts = shortcuts;
}
public synchronized void setStartRecordShortcuts(String[] shortcuts) {
this.startRecordShortcuts = shortcuts;
}
public synchronized void setStopRecordShortcuts(String[] shortcuts) {
this.stopRecordShortcuts = shortcuts;
}
public synchronized void setReplayShortcuts(String[] shortcuts) {
this.replayShortcuts = shortcuts;
}
@Override
public synchronized Response executeCommand(Command command) {
List<Element> elements = new ArrayList<Element>();
Response response = null;
if (command instanceof SelectCommand) {
Element element = getGenerator().generate(
((SelectCommand) command).getData().getKind());
elements.add(element);
SelectResponse selectResponse = ProtocolFactory.eINSTANCE
.createSelectResponse();
selectResponse.getElements().add(element);
response = selectResponse;
} else if (command instanceof Parent) {
Element element = getGenerator().generate("parent");
elements.add(element);
} else if (command instanceof CreateFigure) {
Element element = getGenerator().generate(
ElementKind.DiagramFigure.name());
elements.add(element);
} else if (command instanceof Children) {
Element element = getGenerator().generate(
((Children) command).getElement().getKind());
elements.add(element);
} else if (command instanceof ActivateDirectEdit) {
Element element = getGenerator().generate("control");
elements.add(element);
} else if (command instanceof GetState) {
Element element = getGenerator().generate("State");
elements.add(element);
GetStateResponse getStateResponse = ProtocolFactory.eINSTANCE
.createGetStateResponse();
getStateResponse.setState(element);
response = getStateResponse;
}
CommandTransferKind transferKind = getTransferKind(command);
container.processTransfer(command, elements, transferKind, controls,
replaceIndex, rawEvents);
hookExecuteCommand(command, elements, transferKind, controls,
replaceIndex, rawEvents);
controls = null;
rawEvents.clear();
return response;
}
private CommandTransferKind getTransferKind(Command command) {
CommandTransferKind transferKind = CommandTransferKind.DEFAULT;
replaceIndex = 0;
if (!container.isEmpty() && isReplacable(command)) {
Command last = container.getLastCommand();
skipNext = false;
if (command instanceof FigureMouseCommand) {
transferKind = getKindForFigureMouseCommand((FigureMouseCommand) command, transferKind);
}
if (isReplacable(last, command) && !skipNext) {
// Replace old command
transferKind = CommandTransferKind.REPLACE_PREVIOUS;
}
}
if ((command instanceof SetStatusDialogMode
&& ((SetStatusDialogMode) command).isEnabled())
|| command instanceof SetSWTDialogInfo || command instanceof RapUploadFile) {
transferKind = CommandTransferKind.INSERT_BEFORE_ESSENTIAL_COMMAND;
} else if (command instanceof UpdateControlCommand) {
transferKind = CommandTransferKind.REMOVE;
}
return transferKind;
}
private CommandTransferKind getKindForFigureMouseCommand(FigureMouseCommand command,
CommandTransferKind transferKind) {
// Look into previous drag command and correct down event.
if (command.getKind().equals(MouseCommandKind.DOWN)) {
int skip = 0;
while (container.size() - (1 + skip) >= 0) {
Command ncmd = container.getLastCommand(1 + skip);
if (ncmd instanceof FigureMouseCommand
&& ((FigureMouseCommand) ncmd).getKind()
.equals(MouseCommandKind.DRAG)) {
skip++;
} else {
break;
}
}
if (skip > 0) {
skipNext = true;
transferKind = CommandTransferKind.INSERT_BEFORE;
replaceIndex = skip;
}
}
return transferKind;
}
public synchronized void setControls(Widget... controls) {
if (controls.length > 0) {
this.controls = new ArrayList<Widget>(Arrays.asList(controls));
} else {
this.controls = null;
}
}
public synchronized List<Widget> getControls() {
List<Widget> result = new ArrayList<Widget>();
if (this.controls != null) {
result.addAll(this.controls);
}
return result;
}
private boolean isReplacable(Command current) {
return (current instanceof SetSelection && !TeslaFeatures.getInstance()
.isTrue(TeslaFeatures.RECORD_ALL_SELECTIONS))
|| current instanceof SetText
|| current instanceof MouseCommand
|| current instanceof DragCommand
|| current instanceof CheckItem
|| current instanceof Close
|| current instanceof TypeText
|| current instanceof FigureMouseCommand
|| current instanceof ApplyCellEditor
|| current instanceof SetTextOffset
|| current instanceof SetCaretPosition
|| current instanceof SetCursorOffset
|| current instanceof DragCommand
|| current instanceof DoubleClick
|| current instanceof WaitForRestart
|| current instanceof SetTextSelection
|| current instanceof SetTextSelection2
|| current instanceof HoverAtText
|| current instanceof HoverAtTextOffset
|| current instanceof Type
|| current instanceof ClickText
|| current instanceof SetFocus
|| current instanceof SelectCommand;
}
private synchronized boolean isReplacable(Command last, Command newCommand) {
boolean equals = last.eClass().equals(newCommand.eClass());
boolean ecoreEquals = false;
if (newCommand instanceof WaitForRestart) {
if (last instanceof WaitForState) {
return true;
}
}
if (last instanceof ElementCommand
&& newCommand instanceof ElementCommand) {
Element lastElement = ((ElementCommand) last).getElement();
Element element = ((ElementCommand) newCommand).getElement();
if (EcoreUtil.equals(lastElement, element)) {
ecoreEquals = true;
}
}
if (last instanceof SetFocus) {
if (newCommand instanceof SetFocus) {
return ecoreEquals;
}
if (newCommand instanceof ClickText) {
return ecoreEquals;
}
}
if (last instanceof ClickText && newCommand instanceof SetText
&& ecoreEquals) {
return true;
}
if (newCommand instanceof Type && last instanceof Type && ecoreEquals) {
Type newTypeCmd = (Type) newCommand;
Type lastTypeCmd = (Type) last;
int tempTimes = newTypeCmd.getTimes();
newTypeCmd.setTimes(lastTypeCmd.getTimes());
if (EcoreUtil.equals(lastTypeCmd, newTypeCmd)) {
newTypeCmd.setTimes(lastTypeCmd.getTimes() + 1);
return true;
}
newTypeCmd.setTimes(tempTimes);
return false;
}
if (newCommand instanceof SetTextSelection
&& last instanceof SetTextSelection) {
return ecoreEquals;
}
if (newCommand instanceof SetTextSelection2
&& last instanceof SetTextSelection2) {
return ecoreEquals;
}
if (last instanceof Click && newCommand instanceof Click) {
String lastKind = ((Click) last).getElement().getKind();
if (lastKind.equals(ElementKind.View.name())
|| lastKind.equals(ElementKind.Editor.name())) {
return ecoreEquals;
}
}
if (last instanceof Click && ((Click) last).isDefault()
&& newCommand instanceof DoubleClick) {
return ecoreEquals;
}
if (newCommand instanceof DoubleClick) {
return false;
}
if (last instanceof ApplyCellEditor
&& newCommand instanceof ApplyCellEditor) {
return ecoreEquals;
}
if (equals && last instanceof MouseCommand) {
MouseCommand lastCmd = (MouseCommand) last;
MouseCommand newCmd = (MouseCommand) newCommand;
equals = lastCmd.getKind().equals(newCmd.getKind());
if (lastCmd.getKind().equals(MouseCommandKind.DRAG)) {
return false;
}
if (lastCmd.getKind().equals(MouseCommandKind.MOVE)) {
return isReplacable(last) && isReplacable(newCommand) && equals;
}
}
if (equals && last instanceof FigureMouseCommand) {
FigureMouseCommand lastCmd = (FigureMouseCommand) last;
FigureMouseCommand newCmd = (FigureMouseCommand) newCommand;
equals = lastCmd.getKind().equals(newCmd.getKind());
if (equals && lastCmd.getKind().equals(MouseCommandKind.DRAG)) {
return true;
}
if (lastCmd.getKind().equals(MouseCommandKind.MOVE)) {
return isReplacable(last) && isReplacable(newCommand) && equals;
}
}
if (equals && ecoreEquals && last instanceof CheckItem) {
CheckItem ci1 = (CheckItem) last;
CheckItem ci2 = (CheckItem) newCommand;
EList<String> p1 = ci1.getPath();
EList<String> p2 = ci2.getPath();
if (p1.size() != p2.size()) {
return false;
}
for (int i = 0; i < p1.size(); i++) {
if (!p1.get(i).equals(p2.get(i))) {
return false;
}
}
// Check also for same path.
return ci1.isState() == ci2.isState();
}
if (equals && ecoreEquals && last instanceof TypeText) {
TypeText t1 = (TypeText) last;
TypeText t2 = (TypeText) newCommand;
t2.setText(t1.getText() + t2.getText());
return true;
}
if (last instanceof DragCommand && newCommand instanceof DragCommand) {
DragCommand lastDrag = (DragCommand) last;
DragCommand newDrag = (DragCommand) newCommand;
if (lastDrag.getKind().equals(newDrag.getKind())
&& newDrag.getKind().equals(DragKind.OVER)) {
return true;
}
return false;
}
return isReplacable(last) && isReplacable(newCommand) && equals
&& ecoreEquals;
}
protected void hookExecuteCommand(Command command, List<Element> elements,
CommandTransferKind kind, List<Widget> controls, int index,
List<RawEvent> rawEvents) {
}
public ElementGenerator getGenerator() {
return generator;
}
public synchronized void clear() {
// this.generator = new ElementGenerator();
this.container.clear();
this.controls = null;
this.rawEvents.clear();
}
public void generatorsClear() {
this.generator = new ElementGenerator();
}
public TeslaScenarioContainer getContainer() {
return container;
}
public void removeLast() {
container.removeLast();
hookExecuteCommand(null, null, CommandTransferKind.REPLACE_PREVIOUS,
null, 0, null);
}
public void remove(int index) {
container.remove(index);
hookExecuteCommand(null, null, CommandTransferKind.REMOVE, null, index,
null);
}
}