package com.sap.runlet.abstractexpressionpad.views;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.LinkedList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;
import com.sap.runlet.abstractexpressionpad.Evaluator;
import com.sap.runlet.abstractexpressionpad.Evaluator.ExecuteResult;
import com.sap.runlet.abstractinterpreter.AbstractRunletInterpreter;
import com.sap.runlet.abstractinterpreter.StackFrame;
import com.sap.runlet.abstractinterpreter.objects.RunletObject;
/**
* This sample class demonstrates how to plug-in a new workbench view. The view
* shows data obtained from the model. The sample creates a dummy model on the
* fly, but a real implementation would connect to the model available either in
* this or another plug-in (e.g. the workspace). The view is connected to the
* model using a content provider.
* <p>
* The view uses a label provider to define how model objects should be
* presented in the view. Each view can present the same model objects using
* different labels and icons, if needed. Alternatively, a single label provider
* can be shared between views in order to ensure that objects of the same type
* are presented in the same way everywhere.
* <p>
*/
public abstract class ConsoleView<LinkMetaObject extends EObject,
LinkEndMetaObject extends EObject, MetaClass extends EObject,
TypeUsage extends EObject, ClassUsage extends TypeUsage,
StatementType extends EObject, ExpressionType extends EObject,
SignatureImplementationType extends EObject,
StackFrameType extends StackFrame<LinkEndMetaObject, TypeUsage, ClassUsage, SignatureImplementationType>,
NativeType extends SignatureImplementationType,
InterpreterType extends AbstractRunletInterpreter<MetaClass, TypeUsage, ClassUsage, LinkMetaObject, LinkEndMetaObject, StatementType, ExpressionType, SignatureImplementationType, StackFrameType, NativeType, InterpreterType>,
BlockType extends SignatureImplementationType,
VariableType extends EObject> extends ViewPart {
protected Text output;
private Text errorOutput;
private Text input;
private Button evaluateButton;
private final BlockService<BlockType, VariableType, StatementType, TypeUsage> blockService;
protected Evaluator<MetaClass, TypeUsage, ClassUsage, LinkMetaObject, LinkEndMetaObject, StatementType, ExpressionType,
SignatureImplementationType, StackFrameType, NativeType, InterpreterType, BlockType> evaluator;
private FontRegistry fontRegistry;
protected LinkedList<String> history;
private int historyPosition = 0;
Clipboard clipboard;
private boolean errorOutputShown;
private int sashPos;
/*
* The content provider class is responsible for providing objects to the
* view. It can wrap existing objects in adapters or simply return objects
* as-is. These objects may be sensitive to the current input of the view,
* or ignore it and always show the same content (like Task List, for
* example).
*/
/**
* The constructor.
* @param blockService TODO
*/
public ConsoleView(BlockService<BlockType, VariableType, StatementType, TypeUsage> blockService) {
this.blockService = blockService;
history = new LinkedList<String>();
}
private BlockService<BlockType, VariableType, StatementType, TypeUsage> getBlockService() {
return blockService;
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(final Composite parent) {
fontRegistry = new FontRegistry(parent.getDisplay());
fontRegistry.put("code", new FontData[] { new FontData("Courier New", 10, SWT.NORMAL) }); //$NON-NLS-1$ //$NON-NLS-2$
clipboard = new Clipboard(parent.getDisplay());
errorOutputShown = true;
sashPos = 0;
// set the layout to a FormLayout
FormLayout formLayout = new FormLayout();
parent.setLayout(formLayout);
output = new Text(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
output.setEditable(false);
output.setFont(fontRegistry.get("code")); //$NON-NLS-1$
output.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK));
output.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_GREEN));
output.setText(NLS.bind(Messages.RunletConsoleView_3, getLanguageName()));
output.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.PAUSE) {
createJUnitTestCaseInClipboard();
} else if (e.keyCode == SWT.ESC) {
resetConsole();
}
}
});
final Sash sash = new Sash(parent, SWT.BORDER | SWT.HORIZONTAL);
FormData layoutData = new FormData();
layoutData.left = new FormAttachment(0, 0);
layoutData.right = new FormAttachment(100, 0);
layoutData.top = new FormAttachment(0, 0);
layoutData.bottom = new FormAttachment(sash, 0);
output.setLayoutData(layoutData);
final int limit = 50;
final FormData sashData = new FormData();
sashData.left = new FormAttachment(0, 0);
sashData.top = new FormAttachment(50, 0);
sashData.right = new FormAttachment(100, 0);
sash.setLayoutData(sashData);
sash.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
Rectangle sashRect = sash.getBounds();
Rectangle shellRect = parent.getClientArea();
int right = shellRect.height - sashRect.height - limit;
e.y = Math.max(Math.min(e.y, right), limit);
if (e.y != sashRect.y) {
sashData.top = new FormAttachment(0, e.y);
sashPos = e.y;
parent.layout();
}
}
});
errorOutput = new Text(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
errorOutput.setEditable(false);
errorOutput.setFont(fontRegistry.get("code")); //$NON-NLS-1$
errorOutput.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK));
errorOutput.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_GREEN));
layoutData = new FormData();
layoutData.left = new FormAttachment(0, 0);
layoutData.right = new FormAttachment(100, 0);
layoutData.top = new FormAttachment(sash, 0);
layoutData.bottom = new FormAttachment(90, 0);
errorOutput.setLayoutData(layoutData);
input = new Text(parent, SWT.SINGLE);
input.setEditable(true);
input.setFont(fontRegistry.get("code")); //$NON-NLS-1$
input.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK));
input.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_GREEN));
layoutData = new FormData();
layoutData.left = new FormAttachment(0, 0);
layoutData.right = new FormAttachment(90, 0);
layoutData.top = new FormAttachment(errorOutput, 0);
layoutData.bottom = new FormAttachment(100, 0);
input.setLayoutData(layoutData);
input.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.ARROW_UP) {
historyPosition++;
if (historyPosition >= history.size()) {
historyPosition = history.size() - 1;
} else {
input.setText(history.get(historyPosition));
}
} else if (e.keyCode == SWT.ARROW_DOWN) {
historyPosition--;
if (historyPosition < 0) {
historyPosition = 0;
} else {
input.setText(history.get(historyPosition));
}
} else if (e.keyCode == SWT.Selection) {
if (evaluator != null) {
evaluateStatement();
}
} else if (e.keyCode == SWT.PAGE_UP) {
for (Iterator<String> iterator = history.iterator(); iterator.hasNext();) {
String statement = iterator.next();
if (statement.startsWith(input.getText().trim())) {
input.setText(statement);
}
}
} else if (e.keyCode == SWT.PAUSE) {
createJUnitTestCaseInClipboard();
} else if (e.keyCode == SWT.ESC) {
resetConsole();
} else if (e.keyCode == SWT.PAGE_DOWN) {
FormData errorFD = (FormData) errorOutput.getLayoutData();
FormData inputFD = (FormData) input.getLayoutData();
FormData evalFD = (FormData) evaluateButton.getLayoutData();
FormData sashFD = (FormData) sash.getLayoutData();
FormData outputFD = (FormData) output.getLayoutData();
if (errorOutputShown) {
errorFD.bottom = new FormAttachment(0, 0);
errorOutput.setLayoutData(errorFD);
inputFD.top = new FormAttachment(output, 0);
input.setLayoutData(inputFD);
evalFD.top = new FormAttachment(output, 0);
evaluateButton.setLayoutData(evalFD);
outputFD.bottom = new FormAttachment(90, 0);
output.setLayoutData(outputFD);
sashFD.top = new FormAttachment(0, 0);
sash.setLayoutData(sashFD);
} else {
errorFD.bottom = new FormAttachment(90, 0);
errorOutput.setLayoutData(errorFD);
inputFD.top = new FormAttachment(errorOutput, 0);
input.setLayoutData(inputFD);
evalFD.top = new FormAttachment(errorOutput, 0);
evaluateButton.setLayoutData(evalFD);
outputFD.bottom = new FormAttachment(sash, 0);
output.setLayoutData(outputFD);
if (sashPos == 0)
sashFD.top = new FormAttachment(50, 0);
else
sashFD.top = new FormAttachment(0, sashPos);
sash.setLayoutData(sashFD);
}
errorOutputShown = !errorOutputShown;
errorOutput.getParent().layout();
}
}
});
evaluateButton = new Button(parent, 0);
evaluateButton.setText(Messages.RunletConsoleView_5);
evaluateButton.setEnabled(false);
layoutData = new FormData();
layoutData.left = new FormAttachment(input, 0);
layoutData.right = new FormAttachment(100, 0);
layoutData.top = new FormAttachment(errorOutput, 0);
layoutData.bottom = new FormAttachment(100, 0);
layoutData.height = 15;
evaluateButton.setLayoutData(layoutData);
hookActions();
parent.getDisplay().asyncExec(new Runnable() {
public void run() {
try {
createEvaluator();
initializeHTTPServer();
evaluateButton.setEnabled(true);
output.setText(NLS.bind(Messages.RunletConsoleView_7, getLanguageName()));
} catch (Exception e) {
output.setText(NLS.bind(Messages.RunletConsoleView_8, getLanguageName()));
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
output.append(stackTrace.getBuffer().toString());
}
}
});
}
protected abstract void createEvaluator();
public void dispose() {
super.dispose();
shutdownHTTPServer();
clipboard.dispose();
}
protected abstract void shutdownHTTPServer();
protected abstract void initializeHTTPServer();
private void hookActions() {
evaluateButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
evaluateStatement();
}
});
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
input.setFocus();
}
private void evaluateStatement() {
assert evaluator != null;
String statement = input.getText().trim();
if (statement.length() > 0) {
historyPosition = 0;
if (history.size() == 0) {
history.add(statement);
} else if (!history.peek().equals(statement)) {
history.add(0, statement);
}
output.append(statement + "\n"); //$NON-NLS-1$
try {
if (statement.charAt(0) == '!') {
doEnvironmentInspection(statement);
} else {
doRiverEvaluation(statement);
}
} catch (Exception e1) {
// TODO can you change to a different color here?
StringWriter stackTrace = new StringWriter();
e1.printStackTrace(new PrintWriter(stackTrace));
output.append(stackTrace.getBuffer().toString());
}
output.append("> "); //$NON-NLS-1$
input.selectAll();
}
}
private void doEnvironmentInspection(String statement) {
if (statement.equals("!context")) { //$NON-NLS-1$
BlockType block = evaluator.getInterpreterOutermostBlockWrapper();
output.append(Messages.RunletConsoleView_2);
for (VariableType variable : getBlockService().getVariables(block)) {
output.append(getBlockService().getVariableName(variable));
output.append(" <" + getBlockService().getVariableType(variable).toString() + ">\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
output.append(Messages.RunletConsoleView_16);
for (StatementType stmnt : getBlockService().getStatements(block)) {
output.append(stmnt.getClass().toString() + "\n"); //$NON-NLS-1$
}
} else if (statement.equals("!stack")) { //$NON-NLS-1$
output.append(Messages.RunletConsoleView_1);
output.append(evaluator.getStackFrame().renderAsString());
} else if (statement.equals("!http_reload")) { //$NON-NLS-1$
reloadHttp();
} else if (statement.equals("!help")) { //$NON-NLS-1$
output.append(Messages.RunletConsoleView_23);
output.append(Messages.RunletConsoleView_24);
output.append(Messages.RunletConsoleView_25);
output.append(Messages.RunletConsoleView_26);
output.append(Messages.RunletConsoleView_27);
output.append(Messages.RunletConsoleView_28);
output.append(Messages.RunletConsoleView_29);
output.append(Messages.RunletConsoleView_30);
output.append(Messages.RunletConsoleView_42);
} else {
output.append(Messages.RunletConsoleView_31 + statement + Messages.RunletConsoleView_32);
}
output.append(Messages.RunletConsoleView_33);
}
protected abstract void reloadHttp();
private void doRiverEvaluation(String statement) throws Exception {
ExecuteResult<LinkEndMetaObject, TypeUsage, ClassUsage> result = evaluator.execute(statement);
if (result.getErrors().length > 0) {
StringBuilder errorString = new StringBuilder(result.getErrors().length * 100);
for (String errorMessage : result.getErrors()) {
errorString.append(" "); //$NON-NLS-1$
errorString.append(errorMessage);
errorString.append('\n');
}
errorOutput.append(errorString.toString());
}
for (RunletObject<LinkEndMetaObject, TypeUsage, ClassUsage> riverObject : result.getResult()) {
StringBuilder resultString = new StringBuilder(result.getResult().length * 30);
if (riverObject == null) {
resultString.append("<null>\n"); //$NON-NLS-1$
} else {
resultString.append(riverObject.toString()).append("\n"); //$NON-NLS-1$
}
output.append(resultString.toString());
}
}
private void createJUnitTestCaseInClipboard() {
// 'Pause' Key - Copy JUnit test method to clipboard
TextTransfer textTransfer = TextTransfer.getInstance();
Transfer[] transfers = new Transfer[] { textTransfer };
Object[] data = new Object[] { JavaTestCaseBuilder.buildTestCase(history) };
clipboard.setContents(data, transfers);
output.append(Messages.RunletConsoleView_38);
}
protected void resetConsole() {
// 'POS1' Key - Clear history
evaluateButton.setEnabled(false);
history.clear();
shutdownHTTPServer();
createEvaluator();
initializeHTTPServer();
evaluateButton.setEnabled(true);
output.append(Messages.RunletConsoleView_40);
evaluateButton.setEnabled(true);
errorOutput.setText("");
}
protected abstract String getLanguageName();
}