Package com.dubture.twig.ui.editor

Source Code of com.dubture.twig.ui.editor.TwigStructuredEditor$OccurrencesFinderJob

/*******************************************************************************
* This file is part of the Twig eclipse plugin.
*
* (c) Robert Gruendler <r.gruendler@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
package com.dubture.twig.ui.editor;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
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.dltk.core.IMember;
import org.eclipse.dltk.core.ISourceRange;
import org.eclipse.dltk.core.ISourceReference;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.internal.ui.actions.CompositeActionGroup;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ISelectionValidator;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.ImageUtilities;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.php.internal.core.documentModel.parser.PhpSourceParser;
import org.eclipse.php.internal.core.documentModel.partitioner.PHPPartitionTypes;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.editor.PHPStructuredEditor;
import org.eclipse.php.internal.ui.util.PHPPluginImages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.ActionGroup;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
import org.eclipse.wst.sse.ui.internal.reconcile.ReconcileAnnotationKey;
import org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation;

import com.dubture.twig.core.documentModel.dom.IImplForTwig;
import com.dubture.twig.core.documentModel.parser.TwigSourceParser;
import com.dubture.twig.core.search.IOccurrencesFinder;
import com.dubture.twig.core.search.IOccurrencesFinder.OccurrenceLocation;
import com.dubture.twig.ui.actions.TwigRefactorActionGroup;

/**
*
* A modified {@link PHPStructuredEditor} for Twig templates.
*
* Modifications concerning:
*
* - attaching {@link TwigSourceParser} instead of {@link PhpSourceParser} -
* finding occurences
*
*/
@SuppressWarnings({"restriction", "unchecked"})
public class TwigStructuredEditor extends PHPStructuredEditor
{

    private OccurrencesFinderJob fOccurrencesFinderJob;
    /** The occurrences finder job canceler */
    private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler;

    private ISelection fForcedMarkOccurrencesSelection;

    private CompositeActionGroup contextMenuGroup;

    private TwigRefactorActionGroup refactorGroup = null;

    /**
     * Holds the current occurrence annotations.
     *
     * @since 3.4
     */
    private Annotation[] fOccurrenceAnnotations = null;

    public TwigStructuredEditor()
    {
      setDocumentProvider(DLTKUIPlugin.getDocumentProvider());
    }

    private TwigRefactorActionGroup getRefactorGroup()
    {

        if (refactorGroup != null)
            return refactorGroup;

        refactorGroup = new TwigRefactorActionGroup(this);
        return refactorGroup;

    }

    @Override
    protected void createActions()
    {

        super.createActions();

        contextMenuGroup = new CompositeActionGroup(
                new ActionGroup[]{getRefactorGroup()});

    }

    public ActionGroup getActionGroup()
    {

        CompositeActionGroup group = (CompositeActionGroup) super
                .getActionGroup();
        group.addGroup(getRefactorGroup());
        return group;

    }

    @Override
    public void editorContextMenuAboutToShow(IMenuManager menu)
    {
        super.editorContextMenuAboutToShow(menu);

        if (contextMenuGroup != null) {
            ActionContext context = new ActionContext(getSelectionProvider()
                    .getSelection());
            contextMenuGroup.setContext(context);
            contextMenuGroup.fillContextMenu(menu);
            contextMenuGroup.setContext(null);
        }
    }

    /**
     * TODO: check if this smarty code still applies in the twig editor. That's
     * just copy/pasted from the smarty editor.
     */
    @Override
    protected void doSetInput(IEditorInput input) throws CoreException
    {

        IResource resource = null;
        if (input instanceof IFileEditorInput) {
            // This is the existing workspace file
            final IFileEditorInput fileInput = (IFileEditorInput) input;
            resource = fileInput.getFile();
        } else if (input instanceof IStorageEditorInput) {
            // This kind of editor input usually means non-workspace file, like
            // PHP file which comes from include path, remote file which comes
            // from
            // Web server while debugging, file from ZIP archive, etc...

            // final IStorageEditorInput editorInput = (IStorageEditorInput)
            // input;
            // final IStorage storage = editorInput.getStorage();

            // if (storage instanceof ZipEntryStorage) {
            // resource = ((ZipEntryStorage) storage).getProject();
            // }
        }

        if (resource instanceof IFile) {

            String ext = resource.getFileExtension();

            // TODO: Get the associated content types for file extensions
            // from preferences
            if (ext != null && (ext.contains("twig") || ext.contains("html"))) {
                TwigSourceParser.editFile.set(resource);
                super.doSetInput(input);

            } else {
                super.doSetInput(input);
            }
        } else {
            super.doSetInput(input);
        }

        ImageDescriptor imageDescriptor = input.getImageDescriptor();
        if (imageDescriptor != null) {
            setTitleImage(JFaceResources.getResources().createImageWithDefault(
                    imageDescriptor));
        }
        if (isShowingOverrideIndicators()) {
            installOverrideIndicator(true);
        }
    }

    @Override
    protected StructuredTextViewer createStructedTextViewer(Composite parent,
            IVerticalRuler verticalRuler, int styles)
    {

        return new TwigStructuredTextViewer(this, parent, verticalRuler,
                getOverviewRuler(), isOverviewRulerVisible(), styles);
    }


    class OccurrencesFinderJobCanceler implements IDocumentListener,
            ITextInputListener
    {

        public void install()
        {
            ISourceViewer sourceViewer = getSourceViewer();
            if (sourceViewer == null)
                return;

            StyledText text = sourceViewer.getTextWidget();
            if (text == null || text.isDisposed())
                return;

            sourceViewer.addTextInputListener(this);

            IDocument document = sourceViewer.getDocument();
            if (document != null)
                document.addDocumentListener(this);
        }

        public void uninstall()
        {
            ISourceViewer sourceViewer = getSourceViewer();
            if (sourceViewer != null)
                sourceViewer.removeTextInputListener(this);

            IDocumentProvider documentProvider = getDocumentProvider();
            if (documentProvider != null) {
                IDocument document = documentProvider
                        .getDocument(getEditorInput());
                if (document != null)
                    document.removeDocumentListener(this);
            }
        }

        /*
         * @see
         * org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged
         * (org.eclipse.jface.text.DocumentEvent)
         */
        public void documentAboutToBeChanged(DocumentEvent event)
        {
            if (fOccurrencesFinderJob != null)
                fOccurrencesFinderJob.doCancel();
        }

        /*
         * @see
         * org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse
         * .jface.text.DocumentEvent)
         */
        public void documentChanged(DocumentEvent event)
        {
        }

        /*
         * @see
         * org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged
         * (org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
         */
        public void inputDocumentAboutToBeChanged(IDocument oldInput,
                IDocument newInput)
        {
            if (oldInput == null)
                return;

            oldInput.removeDocumentListener(this);
        }

        /*
         * @see
         * org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org
         * .eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
         */
        public void inputDocumentChanged(IDocument oldInput, IDocument newInput)
        {
            if (newInput == null)
                return;
            newInput.addDocumentListener(this);
        }
    }

    /**
     * Finds and marks occurrence annotations.
     *
     * @since 3.0
     */
    class OccurrencesFinderJob extends Job
    {

        private final IDocument fDocument;
        private final ISelection fSelection;
        private final ISelectionValidator fPostSelectionValidator;
        private boolean fCanceled = false;
        private final OccurrenceLocation[] fLocations;

        public OccurrencesFinderJob(IDocument document,
                OccurrenceLocation[] locations, ISelection selection)
        {
            super("mark occrrences job name"); // TODO should externals
            fDocument = document;
            fSelection = selection;
            fLocations = locations;

            if (getSelectionProvider() instanceof ISelectionValidator)
                fPostSelectionValidator = (ISelectionValidator) getSelectionProvider();
            else
                fPostSelectionValidator = null;
        }

        // cannot use cancel() because it is declared final
        void doCancel()
        {
            fCanceled = true;
            cancel();
        }

        private boolean isCanceled(IProgressMonitor progressMonitor)
        {
            return fCanceled
                    || progressMonitor.isCanceled()
                    || fPostSelectionValidator != null
                    && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection)
                    || LinkedModeModel.hasInstalledModel(fDocument);
        }

        /*
         * @see Job#run(org.eclipse.core.runtime.IProgressMonitor)
         */
        public IStatus run(IProgressMonitor progressMonitor)
        {
            if (isCanceled(progressMonitor))
                return Status.CANCEL_STATUS;

            ITextViewer textViewer = getTextViewer();
            if (textViewer == null)
                return Status.CANCEL_STATUS;

            IDocument document = textViewer.getDocument();
            if (document == null)
                return Status.CANCEL_STATUS;

            IDocumentProvider documentProvider = getDocumentProvider();
            if (documentProvider == null)
                return Status.CANCEL_STATUS;

            IAnnotationModel annotationModel = documentProvider
                    .getAnnotationModel(getEditorInput());
            if (annotationModel == null)
                return Status.CANCEL_STATUS;

            // Add occurrence annotations
            int length = fLocations.length;
            Map<Annotation, Position> annotationMap = new HashMap<Annotation, Position>(
                    length);
            for (int i = 0; i < length; i++) {

                if (isCanceled(progressMonitor))
                    return Status.CANCEL_STATUS;

                OccurrenceLocation location = fLocations[i];
                Position position = new Position(location.getOffset(),
                        location.getLength());

                String description = location.getDescription();
                String annotationType = (location.getFlags() == IOccurrencesFinder.F_WRITE_OCCURRENCE)
                        ? "org.eclipse.php.ui.occurrences.write" : "org.eclipse.php.ui.occurrences"; //$NON-NLS-1$ //$NON-NLS-2$

                // create an annotation to mark the occurrence
                ReconcileAnnotationKey reconcileAnnotationKey = new ReconcileAnnotationKey(
                        null, PHPPartitionTypes.PHP_DEFAULT,
                        ReconcileAnnotationKey.TOTAL);
                TemporaryAnnotation annotation = new TemporaryAnnotation(
                        position, annotationType, description,
                        reconcileAnnotationKey)
                {

                    // Supply an occurrence image to display in the vertical
                    // ruler
                    @Override
                    public void paint(GC gc, Canvas canvas, Rectangle r)
                    {
                        ImageUtilities.drawImage(
                                PHPUiPlugin.getImageDescriptorRegistry().get(
                                        PHPPluginImages.DESC_OBJS_OCCURRENCES),
                                gc, canvas, r, SWT.CENTER, SWT.TOP);
                    }

                };
                annotationMap.put(annotation, position);
            }

            if (isCanceled(progressMonitor))
                return Status.CANCEL_STATUS;

            synchronized (getLockObject(annotationModel)) {
                if (annotationModel instanceof IAnnotationModelExtension) {
                    ((IAnnotationModelExtension) annotationModel)
                            .replaceAnnotations(fOccurrenceAnnotations,
                                    annotationMap);
                } else {
                    removeTwigOccurrenceAnnotations();
                    for (Map.Entry<Annotation, Position> entry : annotationMap
                            .entrySet()) {
                        annotationModel.addAnnotation(entry.getKey(),
                                entry.getValue());
                    }
                }
                fOccurrenceAnnotations = annotationMap.keySet().toArray(
                        new Annotation[annotationMap.keySet().size()]);
            }

            return Status.OK_STATUS;
        }
    }

    private Object getLockObject(IAnnotationModel annotationModel)
    {
        if (annotationModel instanceof ISynchronizable) {
            Object lock = ((ISynchronizable) annotationModel).getLockObject();
            if (lock != null)
                return lock;
        }
        return annotationModel;
    }

    private void removeTwigOccurrenceAnnotations()
    {

        IDocumentProvider documentProvider = getDocumentProvider();
        if (documentProvider == null)
            return;

        IAnnotationModel annotationModel = documentProvider
                .getAnnotationModel(getEditorInput());
        if (annotationModel == null || fOccurrenceAnnotations == null)
            return;

        synchronized (getLockObject(annotationModel)) {
            if (annotationModel instanceof IAnnotationModelExtension) {
                ((IAnnotationModelExtension) annotationModel)
                        .replaceAnnotations(fOccurrenceAnnotations, null);
            } else {
                for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++)
                    annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
            }
            fOccurrenceAnnotations = null;
        }
    }

    @Override
    protected void uninstallOccurrencesFinder()
    {
        // TODO Auto-generated method stub
        super.uninstallOccurrencesFinder();

        if (fOccurrencesFinderJob != null) {
            fOccurrencesFinderJob.cancel();
            fOccurrencesFinderJob = null;
        }

        if (fOccurrencesFinderJobCanceler != null) {
            fOccurrencesFinderJobCanceler.uninstall();
            fOccurrencesFinderJobCanceler = null;
        }

        removeTwigOccurrenceAnnotations();
    }

    protected void setSelection(ISourceReference reference, boolean moveCursor)
    {
        if (getSelectionProvider() == null)
            return;

        final ISelection[] selections = new ISelection[1];
        Display.getDefault().syncExec(new Runnable() {
            public void run() {
                selections[0] = getSelectionProvider().getSelection();
            }
        });

        if (selections[0] == null) {
            return;
        }

        final ISelection selection = selections[0];
        if (selection instanceof TextSelection) {
            TextSelection textSelection = (TextSelection) selection;
            if (textSelection instanceof IStructuredSelection) {
                Object firstElement = ((IStructuredSelection) textSelection)
                        .getFirstElement();
                if (firstElement instanceof IImplForTwig) {
                    ((IImplForTwig) firstElement)
                            .setModelElement(getModelElement());
                }
            }
            // PR 39995: [navigation] Forward history cleared after going back
            // in navigation history:
            // mark only in navigation history if the cursor is being moved
            // (which it isn't if
            // this is called from a PostSelectionEvent that should only update
            // the magnet)
            if (moveCursor
                    && (textSelection.getOffset() != 0 || textSelection
                            .getLength() != 0))
                markInNavigationHistory();
        }
        if (reference != null) {
            StyledText textWidget = null;
            ISourceViewer sourceViewer = getSourceViewer();
            if (sourceViewer != null)
                textWidget = sourceViewer.getTextWidget();
            if (textWidget == null)
                return;
            try {
                ISourceRange range = null;
                range = reference.getSourceRange();
                if (range == null)
                    return;
                int offset = range.getOffset();
                int length = range.getLength();
                if (offset < 0 || length < 0)
                    return;
                setHighlightRange(offset, length, moveCursor);
                if (!moveCursor)
                    return;
                offset = -1;
                length = -1;
                if (reference instanceof IMember) {
                    range = ((IMember) reference).getNameRange();
                    if (range != null) {
                        offset = range.getOffset();
                        length = range.getLength();
                    }
                }
                if (offset > -1 && length > 0) {
                    try {
                        textWidget.setRedraw(false);
                        sourceViewer.revealRange(offset, length);
                        sourceViewer.setSelectedRange(offset, length);
                    } finally {
                        textWidget.setRedraw(true);
                    }
                    markInNavigationHistory();
                }
            } catch (ModelException x) {
            } catch (IllegalArgumentException x) {
            }
        } else if (moveCursor) {
            resetHighlightRange();
            markInNavigationHistory();
        }
    }

}
TOP

Related Classes of com.dubture.twig.ui.editor.TwigStructuredEditor$OccurrencesFinderJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.