/*******************************************************************************
* Copyright (c) 2011 Sebastian Benz and others.
* 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:
* Sebastian Benz - initial API and implementation
*******************************************************************************/
package org.xrepl.ui.console;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.ITextListener;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextEvent;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.actions.ClearOutputAction;
import org.eclipse.ui.part.Page;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import org.xrepl.EvaluationController;
import org.xrepl.InputField;
import org.xrepl.OutputView;
import org.xrepl.ui.embedded.EmbeddedXtextEditor;
import org.xrepl.ui.internal.XreplActivator;
import com.google.inject.Inject;
import com.google.inject.Injector;
public class XreplConsolePage extends Page {
public class CancelAction extends Action {
public CancelAction() {
init();
}
protected void init() {
setDisabledImageDescriptor(getImage("dlcl16/cancel.gif"));
setImageDescriptor(getImage("elcl16/cancel.gif"));
setEnabled(false);
}
@Override
public void run() {
if (evaluationJob != null) {
evaluationJob.cancel();
}
}
@Override
public String getToolTipText() {
return "Cancel execution";
}
protected ImageDescriptor getImage(String path) {
return XreplActivator.getImageDescriptor("icons/" + path);
}
}
private class EvaluationJob extends Job {
private final String input;
private EvaluationJob(String input) {
super("Evaluating...");
this.input = input;
setPriority(INTERACTIVE);
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
evaluator.evaluate(input, asCancelIndicator(monitor));
cancelAction.setEnabled(false);
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
} else {
return Status.OK_STATUS;
}
}
protected CancelIndicator asCancelIndicator(
final IProgressMonitor monitor) {
return new CancelIndicator() {
public boolean isCanceled() {
return monitor.isCanceled();
}
};
}
}
private class ResetAndClearAction extends ClearOutputAction {
ResetAndClearAction() {
super(outputViewer);
}
@Override
public String getToolTipText() {
return "Resets the interpreter";
}
@Override
public void run() {
super.run();
sourceEditor.update("");
evaluator.reset();
}
}
private Composite page;
private ITextViewer outputViewer;
private EObject context;
private ISelectionService selectionService;
private ISelectionListener selectionListener;
private EmbeddedXtextEditor sourceEditor;
private EvaluationController evaluator;
private ConsoleOutputView.Factory outputWrapperFactory;
private OutputView outputViewWrapper;
private final EvaluationController.Factory documentEvaluatorFactory;
private final ConsoleInputField.Factory inputWrapperFactory;
private InputField inputViewWrapper;
@Inject
private Injector injector;
private CancelAction cancelAction;
private Job evaluationJob;
@Inject
public XreplConsolePage(
EvaluationController.Factory documentEvaluatorFactory,
ConsoleOutputView.Factory outputFactory,
ConsoleInputField.Factory inputFieldFactory) {
this.documentEvaluatorFactory = documentEvaluatorFactory;
this.outputWrapperFactory = outputFactory;
this.inputWrapperFactory = inputFieldFactory;
}
@Override
public void createControl(Composite parent) {
createPanel(parent);
createOutputViewer();
createEditor();
createDocumentEvaluator();
registerSelectionListener();
createActions();
setFocus();
}
private void createEditor() {
sourceEditor = new EmbeddedXtextEditor(page, injector);
sourceEditor.getViewer().addTextListener(new ITextListener() {
public void textChanged(TextEvent event) {
if (event.getDocumentEvent() == null) {
return;
}
if (evaluator.isEvaluationTrigger(TextChangeEventWrapper
.wrap(event))) {
triggerEvaluation();
}
}
});
}
private void triggerEvaluation() {
getDocument().readOnly(new IUnitOfWork<Object, XtextResource>() {
public Object exec(XtextResource state) throws Exception {
final String input = getDocument().get();
cancelAction.setEnabled(true);
evaluationJob = new EvaluationJob(input);
evaluationJob.schedule();
return null;
}
});
}
private void createPanel(Composite parent) {
page = new SashForm(parent, SWT.VERTICAL | SWT.LEFT_TO_RIGHT);
}
private void createActions() {
ResetAndClearAction resetAndClear = createResetAndClearAction();
cancelAction = createCancelAction();
addToMenu(resetAndClear, cancelAction);
addToToolbar(IConsoleConstants.OUTPUT_GROUP, resetAndClear);
addToToolbar(IConsoleConstants.LAUNCH_GROUP, cancelAction);
}
protected CancelAction createCancelAction() {
return new CancelAction();
}
protected void addToToolbar(String group, Action action) {
IToolBarManager toolbar = getSite().getActionBars().getToolBarManager();
toolbar.appendToGroup(group, action);
}
protected void addToMenu(Action... actions) {
IMenuManager menu = getSite().getActionBars().getMenuManager();
for (Action action : actions) {
menu.add(action);
}
}
protected ResetAndClearAction createResetAndClearAction() {
return new ResetAndClearAction();
}
private void registerSelectionListener() {
selectionListener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart part,
ISelection selection) {
XreplConsolePage.this.selectionChanged(selection);
}
};
selectionService = getSite().getWorkbenchWindow().getSelectionService();
selectionService.addPostSelectionListener(selectionListener);
selectionChanged(selectionService.getSelection());
}
private void createOutputViewer() {
outputViewer = new TextViewer(page, SWT.BORDER | SWT.MULTI
| SWT.V_SCROLL | SWT.H_SCROLL);
outputViewer.getTextWidget().setLayoutData(
new GridData(GridData.FILL_BOTH));
outputViewer.getTextWidget().setFont(
JFaceResources.getFont(JFaceResources.TEXT_FONT));
outputViewer.setEditable(false);
outputViewer.setDocument(new Document());
}
private void createDocumentEvaluator() {
outputViewWrapper = outputWrapperFactory.create(outputViewer);
inputViewWrapper = inputWrapperFactory.create(sourceEditor);
evaluator = documentEvaluatorFactory.create(inputViewWrapper,
outputViewWrapper);
}
private IXtextDocument getDocument() {
return sourceEditor.getDocument();
}
@Override
public Control getControl() {
return page;
}
@Override
public void setFocus() {
sourceEditor.setFocus();
}
@Override
public void dispose() {
outputViewWrapper.dispose();
selectionService.removePostSelectionListener(selectionListener);
super.dispose();
}
private void selectionChanged(ISelection sel) {
if (sel instanceof IStructuredSelection) {
IStructuredSelection ssel = (IStructuredSelection) sel;
if (!ssel.isEmpty()) {
Object selected = ssel.getFirstElement();
if (selected instanceof EObject) {
context = (EObject) selected;
} else if (selected instanceof IAdaptable) {
context = (EObject) ((IAdaptable) selected)
.getAdapter(EObject.class);
}
}
}
}
}