net.certiv.fluentmark.editor.FluentSourceViewer.java Source code

Java tutorial

Introduction

Here is the source code for net.certiv.fluentmark.editor.FluentSourceViewer.java

Source

/*******************************************************************************
 * Copyright (c) 2016 - 2017 Certiv Analytics 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
 ******************************************************************************/
package net.certiv.fluentmark.editor;

import static org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_BACKGROUND_COLOR;
import static org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_BACKGROUND_DEFAULT_COLOR;
import static org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_FOREGROUND_COLOR;
import static org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SELECTION_FOREGROUND_DEFAULT_COLOR;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND;
import static org.eclipse.ui.texteditor.AbstractTextEditor.PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT;

import java.util.ArrayList;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextPresentationListener;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.source.IOverviewRuler;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

import net.certiv.fluentmark.editor.text.SmartBackspaceManager;
import net.certiv.fluentmark.preferences.Prefs;

/** Source viewer for the editor */
public class FluentSourceViewer extends ProjectionViewer implements IPropertyChangeListener {

    /** Show outline operation id. */
    public static final int SHOW_OUTLINE = 51;
    /** Show element at the current position. */
    public static final int OPEN_STRUCTURE = 52;
    /** Show type hierarchy operation id. */
    public static final int SHOW_HIERARCHY = 53;

    /** Presents outline. */
    private IInformationPresenter fOutlinePresenter;
    /** Presents type structure. */
    private IInformationPresenter fStructurePresenter;
    /** Presents type hierarchy. */
    private IInformationPresenter fHierarchyPresenter;

    /** This viewer's foreground color */
    private Color fForegroundColor;
    /** The viewer's background color */
    private Color fBackgroundColor;
    /** This viewer's selection foreground color */
    private Color fSelectionForegroundColor;
    /** The viewer's selection background color */
    private Color fSelectionBackgroundColor;

    private IPreferenceStore store;
    private SmartBackspaceManager backspaceMgr;
    private boolean isConfigured;
    private boolean isSetVisibleDocumentDelayed = false;

    /** Creates new source viewer. */
    public FluentSourceViewer(Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler,
            boolean isOverviewRulerShowing, int styles, IPreferenceStore store) {
        super(parent, ruler, overviewRuler, isOverviewRulerShowing, styles);
        setPreferenceStore(store);
    }

    public IContentAssistant getContentAssistant() {
        return fContentAssistant;
    }

    @Override
    public void configure(SourceViewerConfiguration configuration) {
        StyledText textWidget = getTextWidget();

        // Prevent access to colors disposed in unconfigure().
        if (textWidget != null && !textWidget.isDisposed()) {
            Color foregroundColor = textWidget.getForeground();
            if (foregroundColor != null && foregroundColor.isDisposed()) {
                textWidget.setForeground(null);
            }
            Color backgroundColor = textWidget.getBackground();
            if (backgroundColor != null && backgroundColor.isDisposed()) {
                textWidget.setBackground(null);
            }
        }

        super.configure(configuration);

        if (configuration instanceof FluentSourceViewerConfiguration) {

            // FluentSourceViewerConfiguration cConfiguration = (FluentSourceViewerConfiguration)
            // configuration;
            //
            // fOutlinePresenter = cConfiguration.getOutlinePresenter(this, false);
            // if (fOutlinePresenter != null) {
            // fOutlinePresenter.install(this);
            // }
            // fStructurePresenter = cConfiguration.getOutlinePresenter(this, true);
            // if (fStructurePresenter != null) {
            // fStructurePresenter.install(this);
            // }
            // fHierarchyPresenter = cConfiguration.getHierarchyPresenter(this);
            // if (fHierarchyPresenter != null) {
            // fHierarchyPresenter.install(this);
            // }

            if (textWidget != null) {
                textWidget.setFont(JFaceResources.getFont(Prefs.EDITOR_TEXT_FONT));
            }
        }
        if (store != null) {
            this.store.addPropertyChangeListener(this);
            initializeViewerColors();
        }
        isConfigured = true;
    }

    protected void initializeViewerColors() {
        if (store != null) {

            StyledText styledText = getTextWidget();
            Color color = null;

            // ----------- foreground color --------------------
            if (!store.getBoolean(PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT)) {
                color = createColor(store, PREFERENCE_COLOR_FOREGROUND, styledText.getDisplay());
                styledText.setForeground(color);
            }
            if (fForegroundColor != null)
                fForegroundColor.dispose();
            fForegroundColor = color;

            // ---------- background color ----------------------
            if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
                color = createColor(store, PREFERENCE_COLOR_BACKGROUND, styledText.getDisplay());
                styledText.setBackground(color);
            }
            if (fBackgroundColor != null)
                fBackgroundColor.dispose();
            fBackgroundColor = color;

            // ----------- selection foreground color --------------------
            if (!store.getBoolean(EDITOR_SELECTION_FOREGROUND_DEFAULT_COLOR)) {
                color = createColor(store, EDITOR_SELECTION_FOREGROUND_COLOR, styledText.getDisplay());
                styledText.setSelectionForeground(color);
            }
            if (fSelectionForegroundColor != null)
                fSelectionForegroundColor.dispose();
            fSelectionForegroundColor = color;

            // ---------- selection background color ----------------------
            if (!store.getBoolean(EDITOR_SELECTION_BACKGROUND_DEFAULT_COLOR)) {
                color = createColor(store, EDITOR_SELECTION_BACKGROUND_COLOR, styledText.getDisplay());
                styledText.setSelectionBackground(color);
            }
            if (fSelectionBackgroundColor != null)
                fSelectionBackgroundColor.dispose();
            fSelectionBackgroundColor = color;
        }
    }

    /**
     * Creates a color from the information stored in the given preference delta. Returns
     * <code>null</code> if there is no such information available. TODO: move or fix store.getColor
     *
     * @param delta the delta to read from
     * @param key the key used for the lookup in the preference delta
     * @param display the display used create the color
     * @return the created color according to the specification in the preference delta
     */
    public Color createColor(IPreferenceStore store, String key, Display display) {
        RGB rgb = null;
        if (store.contains(key)) {
            if (store.isDefault(key)) {
                rgb = PreferenceConverter.getDefaultColor(store, key);
            } else {
                rgb = PreferenceConverter.getColor(store, key);
            }
            if (rgb != null)
                return new Color(display, rgb);
        }
        return null;
    }

    @Override
    public void unconfigure() {
        if (fOutlinePresenter != null) {
            fOutlinePresenter.uninstall();
            fOutlinePresenter = null;
        }
        if (fStructurePresenter != null) {
            fStructurePresenter.uninstall();
            fStructurePresenter = null;
        }
        if (fHierarchyPresenter != null) {
            fHierarchyPresenter.uninstall();
            fHierarchyPresenter = null;
        }
        if (fForegroundColor != null) {
            fForegroundColor.dispose();
            fForegroundColor = null;
        }
        if (fBackgroundColor != null) {
            fBackgroundColor.dispose();
            fBackgroundColor = null;
        }
        if (store != null)
            this.store.removePropertyChangeListener(this);
        super.unconfigure();
        isConfigured = false;
    }

    @Override
    public void propertyChange(PropertyChangeEvent event) {
        String property = event.getProperty();
        if (PREFERENCE_COLOR_FOREGROUND.equals(property)
                || PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT.equals(property)
                || PREFERENCE_COLOR_BACKGROUND.equals(property)
                || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
                || EDITOR_SELECTION_FOREGROUND_COLOR.equals(property)
                || EDITOR_SELECTION_FOREGROUND_DEFAULT_COLOR.equals(property)
                || EDITOR_SELECTION_BACKGROUND_COLOR.equals(property)
                || EDITOR_SELECTION_BACKGROUND_DEFAULT_COLOR.equals(property)) {
            initializeViewerColors();
        }
    }

    /** Sets the preference delta on this viewer. */
    public void setPreferenceStore(IPreferenceStore store) {
        if (isConfigured && store != null) {
            this.store.removePropertyChangeListener(this);
        }
        this.store = store;
        if (isConfigured && store != null) {
            this.store.addPropertyChangeListener(this);
            initializeViewerColors();
        }
    }

    @Override
    protected void createControl(Composite parent, int styles) {
        // Use LEFT_TO_RIGHT unless otherwise specified.
        if ((styles & SWT.RIGHT_TO_LEFT) == 0 && (styles & SWT.LEFT_TO_RIGHT) == 0) {
            styles |= SWT.LEFT_TO_RIGHT;
        }

        super.createControl(parent, styles);

        backspaceMgr = new SmartBackspaceManager();
        backspaceMgr.install(this);
    }

    @Override
    public void doOperation(int operation) {
        if (getTextWidget() == null) {
            return;
        }
        switch (operation) {
        case SHOW_OUTLINE:
            if (fOutlinePresenter != null) {
                fOutlinePresenter.showInformation();
            }
            return;
        case OPEN_STRUCTURE:
            if (fStructurePresenter != null) {
                fStructurePresenter.showInformation();
            }
            return;
        case SHOW_HIERARCHY:
            if (fHierarchyPresenter != null) {
                fHierarchyPresenter.showInformation();
            }
            return;
        }
        super.doOperation(operation);
    }

    @Override
    public boolean canDoOperation(int operation) {
        switch (operation) {
        case SHOW_OUTLINE:
            return fOutlinePresenter != null;
        case OPEN_STRUCTURE:
            return fStructurePresenter != null;
        case SHOW_HIERARCHY:
            return fHierarchyPresenter != null;
        }
        return super.canDoOperation(operation);
    }

    /** Prepend given listener to the list of presentation listeners */
    public void prependTextPresentationListener(ITextPresentationListener listener) {
        Assert.isNotNull(listener);

        if (fTextPresentationListeners == null) {
            fTextPresentationListeners = new ArrayList<ITextPresentationListener>();
        }

        fTextPresentationListeners.remove(listener);
        fTextPresentationListeners.add(0, listener);
    }

    /**
     * Sets the given reconciler.
     *
     * @param reconciler the reconciler
     */
    void setReconciler(IReconciler reconciler) {
        this.fReconciler = reconciler;
    }

    /**
     * Returns the reconciler.
     *
     * @return the reconciler or <code>null</code> if not set
     */
    IReconciler getReconciler() {
        return fReconciler;
    }

    /**
     * Delays setting the visual document until after the projection has been computed. This method
     * must only be called before the document is set on the viewer.
     * <p>
     * This is a performance optimization to reduce the computation of the text presentation
     * triggered by <code>setVisibleDocument(IDocument)</code>.
     * </p>
     */
    void prepareDelayedProjection() {
        Assert.isTrue(!isSetVisibleDocumentDelayed);
        isSetVisibleDocumentDelayed = true;
    }

    @Override
    protected void setVisibleDocument(IDocument document) {
        if (isSetVisibleDocumentDelayed) {
            isSetVisibleDocumentDelayed = false;
            IDocument previous = getVisibleDocument();
            // will set the visible document if anything is folded
            enableProjection();
            IDocument current = getVisibleDocument();
            // if the visible document was not replaced, continue as usual
            if (current != null && current != previous)
                return;
        }
        super.setVisibleDocument(document);
    }

    @Override
    protected StyleRange modelStyleRange2WidgetStyleRange(StyleRange range) {
        IRegion region = modelRange2WidgetRange(new Region(range.start, range.length));
        if (region != null) { // don't clone the style range, but simply reuse it.
            range.start = region.getOffset();
            range.length = region.getLength();
            return range;
        }
        return null;
    }

    @Override
    public void resetVisibleRegion() {
        super.resetVisibleRegion();
        // re-enable folding if ProjectionViewer failed to due so
        if (store != null && !isProjectionMode())
            enableProjection();
    }

    public SmartBackspaceManager getBackspaceManager() {
        return backspaceMgr;
    }

    @Override
    protected void handleDispose() {
        if (backspaceMgr != null) {
            backspaceMgr.uninstall();
            backspaceMgr = null;
        }
        super.handleDispose();
    }

}