org.eclipse.rcptt.ui.controls.ScriptComposite.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.rcptt.ui.controls.ScriptComposite.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2014 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 v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Xored Software Inc - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.rcptt.ui.controls;

import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.AbstractOperation;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IOperationHistoryListener;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.commands.operations.OperationHistoryEvent;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.resources.IFile;
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.debug.ui.actions.ToggleBreakpointAction;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ITextViewerExtension6;
import org.eclipse.jface.text.IUndoManagerExtension;
import org.eclipse.jface.text.source.AnnotationModel;
import org.eclipse.jface.text.source.AnnotationRulerColumn;
import org.eclipse.jface.text.source.CompositeRuler;
import org.eclipse.jface.text.source.LineNumberRulerColumn;
import org.eclipse.jface.text.source.OverviewRuler;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.AnnotationPreference;
import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;
import org.eclipse.ui.texteditor.MarkerAnnotationPreferences;
import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;

import org.eclipse.rcptt.core.Scenarios;
import org.eclipse.rcptt.core.internal.builder.Q7Builder;
import org.eclipse.rcptt.core.scenario.Scenario;
import org.eclipse.rcptt.core.scenario.ScenarioPackage;
import org.eclipse.rcptt.internal.core.model.Q7InternalTestCase;
import org.eclipse.rcptt.internal.ui.Images;
import org.eclipse.rcptt.internal.ui.Messages;
import org.eclipse.rcptt.internal.ui.Q7UIPlugin;
import org.eclipse.rcptt.ui.debug.ToggleBreakpointEnablementAction;
import org.eclipse.rcptt.ui.editors.TextViewerActionsSupport;
import org.eclipse.rcptt.ui.editors.ecl.EclSourceViewer;
import org.eclipse.rcptt.ui.editors.ecl.EclSourceViewerConfiguration;
import org.eclipse.rcptt.ui.panels.Actions;
import org.eclipse.rcptt.ui.recording.RecordingSupport.RecordingMode;

public class ScriptComposite extends AbstractEmbeddedComposite {

    private static final String SCENARIO_ERROR = "Test case contains errors. Please see error log for details."; //$NON-NLS-1$
    private final Scenario scenario;
    private final IFile file;
    private final IWorkbenchPartSite site;
    private final Shell shell;
    private final int style;
    private final AtomicBoolean scrollLock = new AtomicBoolean(false);
    private Composite control;
    private EclSourceViewer viewer;
    private boolean ignoreChanges;
    private int lastDocumentOperation;

    private final IObservableValue editable = new ComputedValue() {
        @Override
        protected Object calculate() {
            return (Boolean) stopped.getValue();
        }
    };

    private final IObservableValue stopped = new ComputedValue() {
        @Override
        protected Object calculate() {
            return getRecordingMode().equals(RecordingMode.Stopped);
        }
    };

    public ScriptComposite(Q7InternalTestCase model, IFile file, Shell shell, int style) {
        this.scenario = model.getNamedElement();
        this.file = file;
        this.site = null;
        this.shell = shell;
        this.style = style;
    }

    public String getName() {
        return Messages.ScriptComposite_Name;
    }

    public Image getImage() {
        return Images.getImage(Images.PANEL_SCENARIO);
    }

    private RecordingMode getRecordingMode() {
        return (RecordingMode) recordingMode.getValue();
    }

    @SuppressWarnings("restriction")
    @Override
    public void createControl(Composite parent) {
        super.createControl(parent);
        final CompositeRuler ruler = new CompositeRuler();

        DefaultMarkerAnnotationAccess access = new DefaultMarkerAnnotationAccess();

        AnnotationRulerColumn annotations = new AnnotationRulerColumn(12, access);
        ruler.addDecorator(0, annotations);

        LineNumberRulerColumn column = new LineNumberRulerColumn() {
            @Override
            public int getWidth() {
                return super.getWidth() + 10;
            }
        };
        Font font = JFaceResources.getTextFont();
        column.setFont(font);
        column.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
        ruler.addDecorator(1, column);

        OverviewRuler overview = new OverviewRuler(access, 12, EditorsUI.getSharedTextColors());

        MarkerAnnotationPreferences preferences = org.eclipse.ui.internal.editors.text.EditorsPlugin.getDefault()
                .getMarkerAnnotationPreferences();

        AnnotationModel model = file != null ? new ResourceMarkerAnnotationModel(file) : new AnnotationModel();

        Iterator<?> e = preferences.getAnnotationPreferences().iterator();
        while (e.hasNext()) {
            AnnotationPreference preference = (AnnotationPreference) e.next();
            if (preference.contributesToHeader())
                overview.addHeaderAnnotationType(preference.getAnnotationType());
            // annotations.addAnnotationType(preference.getAnnotationType());
        }
        annotations.addAnnotationType(Q7Builder.MARKER_TYPE);

        viewer = new EclSourceViewer(parent, ruler, overview, true,
                SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        final IDocument document = new Document(Scenarios.getScriptContent(scenario));
        viewer.setDocument(document, model);
        viewer.configure(new EclSourceViewerConfiguration());

        SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(viewer, overview, access,
                EditorsUI.getSharedTextColors());

        Iterator<?> it = preferences.getAnnotationPreferences().iterator();
        while (it.hasNext())
            support.setAnnotationPreference((AnnotationPreference) it.next());

        support.install(EditorsUI.getPreferenceStore());

        Control rulerControl = ruler.getControl();
        rulerControl.addMouseListener(new MouseListener() {

            public void mouseUp(final MouseEvent e) {
            }

            public void mouseDoubleClick(MouseEvent e) {
                if (1 == e.button) {
                    ToggleBreakpointAction action = new ToggleBreakpointAction(
                            PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart(),
                            document, ruler);
                    action.update();
                    action.run();
                }
            }

            public void mouseDown(MouseEvent e) {
            }
        });

        String id = AbstractTextEditor.DEFAULT_RULER_CONTEXT_MENU_ID;

        MenuManager manager = new MenuManager(id, id);
        manager.setRemoveAllWhenShown(true);
        manager.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager menu) {
                if (viewer != null && viewer.getTextWidget() != null)
                    viewer.getTextWidget().setFocus();

                ToggleBreakpointAction action1 = new ToggleBreakpointAction(
                        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart(),
                        document, ruler);
                action1.update();
                menu.add(action1);

                ToggleBreakpointEnablementAction action2 = new ToggleBreakpointEnablementAction(viewer, ruler);

                action2.update();
                if (action2.isEnabled()) {
                    menu.add(action2);
                }
            }
        });

        Menu fRulerContextMenu = manager.createContextMenu(rulerControl);
        rulerControl.setMenu(fRulerContextMenu);

        viewer.setEditable((Boolean) editable.getValue());
        editable.addChangeListener(new IChangeListener() {
            public void handleChange(ChangeEvent event) {
                viewer.setEditable((Boolean) editable.getValue());
            }
        });

        GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());

        getOperationHistory().addOperationHistoryListener(new IOperationHistoryListener() {

            public void historyNotification(OperationHistoryEvent event) {
                lastDocumentOperation = event.getEventType();
            }
        });

        viewer.getDocument().addDocumentListener(new IDocumentListener() {
            public void documentChanged(DocumentEvent event) {
                if (ignoreChanges) {
                    return;
                }
                if (!getRecordingMode().equals(RecordingMode.Recording)) {
                    String value = viewer.getDocument().get();
                    if ((value == null || value.length() == 0)
                            && lastDocumentOperation != OperationHistoryEvent.ABOUT_TO_UNDO) {
                        clear();
                    } else {
                        Scenarios.setEclContent(scenario, value);
                    }
                }
            }

            public void documentAboutToBeChanged(DocumentEvent event) {
                // Do nothing
            }
        });

        IChangeListener scenarioContentListener = new IChangeListener() {
            public void handleChange(ChangeEvent event) {
                if (ignoreChanges) {
                    return;
                }
                String script;
                try {
                    script = Scenarios.getScriptContent(scenario);
                } catch (Exception e) {
                    script = SCENARIO_ERROR;
                    Q7UIPlugin.log(e);
                }
                // in some cases after hit upon here from document listener
                // viewer.getDocument() is null
                if (viewer.getDocument() != null) {
                    String doc = viewer.getDocument().get();
                    if (!doc.equals(script)) {
                        viewer.getDocument().set(script);
                        if ((!getRecordingMode().equals(RecordingMode.Stopped)
                                && !getRecordingMode().equals(RecordingMode.Replaying)) && !scrollLock.get()) {
                            try {
                                IDocument document = viewer.getDocument();
                                int length = document.getLength();
                                if (document.getLength() > 0) {
                                    int lineOfOffset = document.getLineOfOffset(length);
                                    int lineOffset = document.getLineOffset(lineOfOffset);
                                    viewer.revealRange(lineOffset, 0);
                                }
                            } catch (BadLocationException e) {
                                Q7UIPlugin.log((e));
                            }
                        }
                    }
                }
            }
        };
        IObservableValue scriptContent = EMFObservables.observeValue(scenario,
                ScenarioPackage.Literals.SCENARIO__CONTENT);
        scriptContent.addChangeListener(scenarioContentListener);

        IObservableValue teslaContent = EMFObservables.observeValue(scenario,
                ScenarioPackage.Literals.SCENARIO__TESLA_CONTENT);
        teslaContent.addChangeListener(scenarioContentListener);

        if (site != null) {
            new TextViewerActionsSupport(viewer, site, editable);
        } else if (shell != null) {
            new TextViewerActionsSupport(viewer, shell, editable);
        }

        control = viewer.getControl();
    }

    public Control getControl() {
        return control;
    }

    public EclSourceViewer getViewer() {
        return viewer;
    }

    @Override
    public void fillActions(IToolBarManager manager) {
        IAction clearAction = new Action() {
            @Override
            public void run() {
                clear();
            }
        };
        clearAction.setImageDescriptor(Images.getImageDescriptor(Images.PANEL_CLEAR));
        clearAction.setToolTipText(Messages.ScriptComposite_ClearActionToolTip);
        dbc.bindValue(Actions.observeEnabled(clearAction), new ComputedValue() {
            @Override
            protected Object calculate() {
                return getRecordingMode().equals(RecordingMode.Stopped);
            }
        });
        manager.add(clearAction);

        if ((style & SWT.SCROLL_LOCK) != 0) {
            IAction scrollLockAction = new Action("", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
                @Override
                public void run() {
                    scrollLock.set(isChecked());
                };
            };
            scrollLockAction.setImageDescriptor(Images.getImageDescriptor(Images.PANEL_SCROLL_LOCK));
            scrollLockAction.setToolTipText(Messages.ScriptComposite_ScrollLockActionToolTip);
            final IObservableValue scrollLockEnabled = new ComputedValue() {
                @Override
                protected Object calculate() {
                    return (Boolean) (!getRecordingMode().equals(RecordingMode.Stopped)
                            && !getRecordingMode().equals(RecordingMode.Replaying));
                }
            };
            dbc.bindValue(Actions.observeEnabled(scrollLockAction), scrollLockEnabled);
            manager.add(scrollLockAction);
        }
    }

    public void clear() {
        // Must clean Tesla first to prevent viewer getting old content
        // from Tesla on Scenario content change
        final IUndoContext undoContext = (viewer instanceof ITextViewerExtension6
                && viewer.getUndoManager() instanceof IUndoManagerExtension)
                        ? ((IUndoManagerExtension) viewer.getUndoManager()).getUndoContext()
                        : null;

        if (undoContext != null) {
            ClearScenarioOperation clearScenario = new ClearScenarioOperation(
                    Messages.ScriptComposite_ClearActionOp, undoContext);
            try {
                getOperationHistory().execute(clearScenario, null, null);
            } catch (ExecutionException e) {
                Q7UIPlugin.log((e));
            }
        } else {
            scenario.setContent(null);
            scenario.setTeslaContent(null);
        }
    }

    private static IOperationHistory getOperationHistory() {
        return PlatformUI.getWorkbench().getOperationSupport().getOperationHistory();
    }

    private class ClearScenarioOperation extends AbstractOperation {

        private EObject fPreservedTeslaContent;
        private EObject fPreservedECLContent;
        private final IUndoContext fUndoContext;

        public ClearScenarioOperation(String label, IUndoContext undoContext) {
            super(label);
            fUndoContext = undoContext;
            addContext(fUndoContext);
        }

        @Override
        public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
            ignoreChanges = true;
            fPreservedECLContent = scenario.getContent();
            fPreservedTeslaContent = scenario.getTeslaContent();
            scenario.setContent(null);
            scenario.setTeslaContent(null);
            viewer.getTextWidget().setText(""); //$NON-NLS-1$
            getOperationHistory().replaceOperation(getOperationHistory().getUndoOperation(fUndoContext),
                    new IUndoableOperation[0]);
            ignoreChanges = false;
            return Status.OK_STATUS;
        }

        @Override
        public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
            return execute(monitor, info);
        }

        @Override
        public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
            ignoreChanges = true;
            scenario.setTeslaContent(fPreservedTeslaContent);
            fPreservedTeslaContent = null;
            scenario.setContent(fPreservedECLContent);
            fPreservedECLContent = null;

            String script;
            try {
                script = Scenarios.getScriptContent(scenario);
            } catch (Exception e) {
                script = SCENARIO_ERROR;
                Q7UIPlugin.log(e);
            }
            viewer.getTextWidget().setText(script);
            getOperationHistory().replaceOperation(getOperationHistory().getUndoOperation(fUndoContext),
                    new IUndoableOperation[0]);
            ignoreChanges = false;

            return Status.OK_STATUS;
        }
    }

}