cz.vutbr.fit.xhriba01.bc.jdt.ui.javaeditor.SemanticHighlightingManager.java Source code

Java tutorial

Introduction

Here is the source code for cz.vutbr.fit.xhriba01.bc.jdt.ui.javaeditor.SemanticHighlightingManager.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2011 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package cz.vutbr.fit.xhriba01.bc.jdt.ui.javaeditor;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextAttribute;

import cz.vutbr.fit.xhriba01.bc.jdt.ui.text.IColorManager;
import cz.vutbr.fit.xhriba01.bc.jdt.ui.text.IColorManagerExtension;
import cz.vutbr.fit.xhriba01.bc.jdt.ui.text.JavaPresentationReconciler;
import cz.vutbr.fit.xhriba01.bc.jdt.ui.text.JavaSourceViewerConfiguration;

/**
 * Semantic highlighting manager
 *
 * @since 3.0
 */
public class SemanticHighlightingManager implements IPropertyChangeListener {

    /**
     * Highlighting.
     */
    static class Highlighting { // TODO: rename to HighlightingStyle

        /** Text attribute */
        private TextAttribute fTextAttribute;
        /** Enabled state */
        private boolean fIsEnabled;

        /**
         * Initialize with the given text attribute.
         * 
         * @param textAttribute
         *            The text attribute
         * @param isEnabled
         *            the enabled state
         */
        public Highlighting(TextAttribute textAttribute, boolean isEnabled) {
            setTextAttribute(textAttribute);
            setEnabled(isEnabled);
        }

        /**
         * @return Returns the text attribute.
         */
        public TextAttribute getTextAttribute() {
            return fTextAttribute;
        }

        /**
         * @param textAttribute
         *            The background to set.
         */
        public void setTextAttribute(TextAttribute textAttribute) {
            fTextAttribute = textAttribute;
        }

        /**
         * @return the enabled state
         */
        public boolean isEnabled() {
            return fIsEnabled;
        }

        /**
         * @param isEnabled
         *            the new enabled state
         */
        public void setEnabled(boolean isEnabled) {
            fIsEnabled = isEnabled;
        }
    }

    /**
     * Highlighted Positions.
     */
    static class HighlightedPosition extends Position {

        /** Highlighting of the position */
        private Highlighting fStyle;

        /** Lock object */
        private Object fLock;

        /**
         * Initialize the styled positions with the given offset, length and
         * foreground color.
         *
         * @param offset
         *            The position offset
         * @param length
         *            The position length
         * @param highlighting
         *            The position's highlighting
         * @param lock
         *            The lock object
         */
        public HighlightedPosition(int offset, int length, Highlighting highlighting, Object lock) {
            super(offset, length);
            fStyle = highlighting;
            fLock = lock;
        }

        /**
         * @return Returns a corresponding style range.
         */
        public StyleRange createStyleRange() {
            int len = 0;
            if (fStyle.isEnabled())
                len = getLength();

            TextAttribute textAttribute = fStyle.getTextAttribute();
            int style = textAttribute.getStyle();
            int fontStyle = style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL);
            StyleRange styleRange = new StyleRange(getOffset(), len, textAttribute.getForeground(),
                    textAttribute.getBackground(), fontStyle);
            styleRange.strikeout = (style & TextAttribute.STRIKETHROUGH) != 0;
            styleRange.underline = (style & TextAttribute.UNDERLINE) != 0;

            return styleRange;
        }

        /**
         * Uses reference equality for the highlighting.
         *
         * @param off
         *            The offset
         * @param len
         *            The length
         * @param highlighting
         *            The highlighting
         * @return <code>true</code> iff the given offset, length and
         *         highlighting are equal to the internal ones.
         */
        public boolean isEqual(int off, int len, Highlighting highlighting) {
            synchronized (fLock) {
                return !isDeleted() && getOffset() == off && getLength() == len && fStyle == highlighting;
            }
        }

        /**
         * Is this position contained in the given range (inclusive)?
         * Synchronizes on position updater.
         *
         * @param off
         *            The range offset
         * @param len
         *            The range length
         * @return <code>true</code> iff this position is not delete and
         *         contained in the given range.
         */
        public boolean isContained(int off, int len) {
            synchronized (fLock) {
                return !isDeleted() && off <= getOffset() && off + len >= getOffset() + getLength();
            }
        }

        public void update(int off, int len) {
            synchronized (fLock) {
                super.setOffset(off);
                super.setLength(len);
            }
        }

        /*
         * @see org.eclipse.jface.text.Position#setLength(int)
         */
        @Override
        public void setLength(int length) {
            synchronized (fLock) {
                super.setLength(length);
            }
        }

        /*
         * @see org.eclipse.jface.text.Position#setOffset(int)
         */
        @Override
        public void setOffset(int offset) {
            synchronized (fLock) {
                super.setOffset(offset);
            }
        }

        /*
         * @see org.eclipse.jface.text.Position#delete()
         */
        @Override
        public void delete() {
            synchronized (fLock) {
                super.delete();
            }
        }

        /*
         * @see org.eclipse.jface.text.Position#undelete()
         */
        @Override
        public void undelete() {
            synchronized (fLock) {
                super.undelete();
            }
        }

        /**
         * @return Returns the highlighting.
         */
        public Highlighting getHighlighting() {
            return fStyle;
        }
    }

    /**
     * Highlighted ranges.
     */
    public static class HighlightedRange extends Region {
        /**
         * The highlighting key as returned by
         * {@link SemanticHighlighting#getPreferenceKey()}.
         */
        private String fKey;

        /**
         * Initialize with the given offset, length and highlighting key.
         * 
         * @param offset
         *            the offset
         * @param length
         *            the length
         * @param key
         *            the highlighting key as returned by
         *            {@link SemanticHighlighting#getPreferenceKey()}
         */
        public HighlightedRange(int offset, int length, String key) {
            super(offset, length);
            fKey = key;
        }

        /**
         * @return the highlighting key as returned by
         *         {@link SemanticHighlighting#getPreferenceKey()}
         */
        public String getKey() {
            return fKey;
        }

        /*
         * @see org.eclipse.jface.text.Region#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object o) {
            return super.equals(o) && o instanceof HighlightedRange && fKey.equals(((HighlightedRange) o).getKey());
        }

        /*
         * @see org.eclipse.jface.text.Region#hashCode()
         */
        @Override
        public int hashCode() {
            return super.hashCode() | fKey.hashCode();
        }
    }

    /** Semantic highlighting presenter */
    private SemanticHighlightingPresenter fPresenter;
    /** Semantic highlighting reconciler */
    private SemanticHighlightingReconciler fReconciler;

    /** Semantic highlightings */
    private SemanticHighlighting[] fSemanticHighlightings;
    /** Highlightings */
    private Highlighting[] fHighlightings;

    /** The editor */
    // private JavaEditor fEditor;
    /** The source viewer */
    private JavaSourceViewer fSourceViewer;
    /** The color manager */
    private IColorManager fColorManager;
    /** The preference store */
    private IPreferenceStore fPreferenceStore;
    /** The source viewer configuration */
    private JavaSourceViewerConfiguration fConfiguration;
    /** The presentation reconciler */
    private JavaPresentationReconciler fPresentationReconciler;

    /** The hard-coded ranges */
    private HighlightedRange[][] fHardcodedRanges;

    /**
     * Install the semantic highlighting on the given editor infrastructure
     *
     * @param editor
     *            The Java editor
     * @param sourceViewer
     *            The source viewer
     * @param colorManager
     *            The color manager
     * @param preferenceStore
     *            The preference store
     */
    public void install(/* JavaEditor editor, */JavaSourceViewer sourceViewer,
            JavaSourceViewerConfiguration sourceViewerConfiguration, IColorManager colorManager,
            IPreferenceStore preferenceStore) {
        // fEditor= editor;
        fSourceViewer = sourceViewer;
        fColorManager = colorManager;
        fPreferenceStore = preferenceStore;
        // if (fEditor != null) {
        fConfiguration = sourceViewerConfiguration;
        fPresentationReconciler = (JavaPresentationReconciler) fConfiguration
                .getPresentationReconciler(sourceViewer);
        // } else {
        // fConfiguration= null;
        // fPresentationReconciler= null;
        // }

        fPreferenceStore.addPropertyChangeListener(this);

        if (isEnabled())
            enable();
    }

    /**
     * Install the semantic highlighting on the given source viewer
     * infrastructure. No reconciliation will be performed.
     *
     * @param sourceViewer
     *            the source viewer
     * @param colorManager
     *            the color manager
     * @param preferenceStore
     *            the preference store
     * @param hardcodedRanges
     *            the hard-coded ranges to be highlighted
     */
    // public void install(JavaSourceViewer sourceViewer, IColorManager
    // colorManager, IPreferenceStore preferenceStore, HighlightedRange[][]
    // hardcodedRanges) {
    // fHardcodedRanges= hardcodedRanges;
    // install(null, sourceViewer, colorManager, preferenceStore);
    // }

    /**
     * Enable semantic highlighting.
     */
    private void enable() {
        initializeHighlightings();

        fPresenter = new SemanticHighlightingPresenter();

        fPresenter.install(fSourceViewer, fPresentationReconciler);

        // if (fEditor != null) {
        fReconciler = new SemanticHighlightingReconciler();
        fReconciler.install(fSourceViewer, fPresenter, fSemanticHighlightings, fHighlightings);
        // } else {
        // fPresenter.updatePresentation(null, createHardcodedPositions(), new
        // HighlightedPosition[0]);
        // }
    }

    /**
     * Computes the hard-coded positions from the hard-coded ranges
     *
     * @return the hard-coded positions
     */
    private HighlightedPosition[] createHardcodedPositions() {
        List<HighlightedPosition> positions = new ArrayList<HighlightedPosition>();
        for (int i = 0; i < fHardcodedRanges.length; i++) {
            HighlightedRange range = null;
            Highlighting hl = null;
            for (int j = 0; j < fHardcodedRanges[i].length; j++) {
                hl = getHighlighting(fHardcodedRanges[i][j].getKey());
                if (hl.isEnabled()) {
                    range = fHardcodedRanges[i][j];
                    break;
                }
            }

            if (range != null)
                positions.add(fPresenter.createHighlightedPosition(range.getOffset(), range.getLength(), hl));
        }
        return positions.toArray(new HighlightedPosition[positions.size()]);
    }

    /**
     * Returns the highlighting corresponding to the given key.
     *
     * @param key
     *            the highlighting key as returned by
     *            {@link SemanticHighlighting#getPreferenceKey()}
     * @return the corresponding highlighting
     */
    private Highlighting getHighlighting(String key) {
        for (int i = 0; i < fSemanticHighlightings.length; i++) {
            SemanticHighlighting semanticHighlighting = fSemanticHighlightings[i];
            if (key.equals(semanticHighlighting.getPreferenceKey()))
                return fHighlightings[i];
        }
        return null;
    }

    /**
     * Uninstall the semantic highlighting
     */
    public void uninstall() {
        disable();

        if (fPreferenceStore != null) {
            fPreferenceStore.removePropertyChangeListener(this);
            fPreferenceStore = null;
        }

        // fEditor= null;
        fSourceViewer = null;
        fColorManager = null;
        fConfiguration = null;
        fPresentationReconciler = null;
        fHardcodedRanges = null;
    }

    /**
     * Disable semantic highlighting.
     */
    private void disable() {
        if (fReconciler != null) {
            fReconciler.uninstall();
            fReconciler = null;
        }

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

        if (fSemanticHighlightings != null)
            disposeHighlightings();
    }

    /**
     * @return <code>true</code> iff semantic highlighting is enabled in the
     *         preferences
     */
    private boolean isEnabled() {
        return SemanticHighlightings.isEnabled(fPreferenceStore);
    }

    /**
     * Initialize semantic highlightings.
     */
    private void initializeHighlightings() {
        fSemanticHighlightings = SemanticHighlightings.getSemanticHighlightings();
        fHighlightings = new Highlighting[fSemanticHighlightings.length];

        for (int i = 0, n = fSemanticHighlightings.length; i < n; i++) {
            SemanticHighlighting semanticHighlighting = fSemanticHighlightings[i];
            String colorKey = SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);

            addColor(colorKey);

            String boldKey = SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
            int style = fPreferenceStore.getBoolean(boldKey) ? SWT.BOLD : SWT.NORMAL;

            String italicKey = SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
            if (fPreferenceStore.getBoolean(italicKey))
                style |= SWT.ITALIC;

            String strikethroughKey = SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
            if (fPreferenceStore.getBoolean(strikethroughKey))
                style |= TextAttribute.STRIKETHROUGH;

            String underlineKey = SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
            if (fPreferenceStore.getBoolean(underlineKey))
                style |= TextAttribute.UNDERLINE;

            boolean isEnabled = fPreferenceStore
                    .getBoolean(SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting));

            //System.out.println("Nastavuji highlighting pro: " + colorKey);
            Color color = fColorManager.getColor(PreferenceConverter.getColor(fPreferenceStore, colorKey));
            //System.out.println("BARVA: "  + color);
            fHighlightings[i] = new Highlighting(new TextAttribute(
                    fColorManager.getColor(PreferenceConverter.getColor(fPreferenceStore, colorKey)), null, style),
                    isEnabled);
        }
    }

    /**
     * Dispose the semantic highlightings.
     */
    private void disposeHighlightings() {
        for (int i = 0, n = fSemanticHighlightings.length; i < n; i++)
            removeColor(SemanticHighlightings.getColorPreferenceKey(fSemanticHighlightings[i]));

        fSemanticHighlightings = null;
        fHighlightings = null;
    }

    /*
     * @see
     * org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
     * .jface.util.PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent event) {
        handlePropertyChangeEvent(event);
    }

    /**
     * Handle the given property change event
     *
     * @param event
     *            The event
     */
    private void handlePropertyChangeEvent(PropertyChangeEvent event) {
        if (fPreferenceStore == null)
            return; // Uninstalled during event notification

        if (fConfiguration != null)
            fConfiguration.handlePropertyChangeEvent(event);

        if (SemanticHighlightings.affectsEnablement(fPreferenceStore, event)) {
            if (isEnabled())
                enable();
            else
                disable();
        }

        if (!isEnabled())
            return;

        boolean refreshNeeded = false;

        for (int i = 0, n = fSemanticHighlightings.length; i < n; i++) {
            SemanticHighlighting semanticHighlighting = fSemanticHighlightings[i];

            String colorKey = SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
            if (colorKey.equals(event.getProperty())) {
                adaptToTextForegroundChange(fHighlightings[i], event);
                fPresenter.highlightingStyleChanged(fHighlightings[i]);
                refreshNeeded = true;
                continue;
            }

            String boldKey = SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
            if (boldKey.equals(event.getProperty())) {
                adaptToTextStyleChange(fHighlightings[i], event, SWT.BOLD);
                fPresenter.highlightingStyleChanged(fHighlightings[i]);
                refreshNeeded = true;
                continue;
            }

            String italicKey = SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
            if (italicKey.equals(event.getProperty())) {
                adaptToTextStyleChange(fHighlightings[i], event, SWT.ITALIC);
                fPresenter.highlightingStyleChanged(fHighlightings[i]);
                refreshNeeded = true;
                continue;
            }

            String strikethroughKey = SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
            if (strikethroughKey.equals(event.getProperty())) {
                adaptToTextStyleChange(fHighlightings[i], event, TextAttribute.STRIKETHROUGH);
                fPresenter.highlightingStyleChanged(fHighlightings[i]);
                refreshNeeded = true;
                continue;
            }

            String underlineKey = SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
            if (underlineKey.equals(event.getProperty())) {
                adaptToTextStyleChange(fHighlightings[i], event, TextAttribute.UNDERLINE);
                fPresenter.highlightingStyleChanged(fHighlightings[i]);
                refreshNeeded = true;
                continue;
            }

            String enabledKey = SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting);
            if (enabledKey.equals(event.getProperty())) {
                adaptToEnablementChange(fHighlightings[i], event);
                fPresenter.highlightingStyleChanged(fHighlightings[i]);
                refreshNeeded = true;
                continue;
            }
        }

        if (refreshNeeded && fReconciler != null)
            fReconciler.refresh();
    }

    private void adaptToEnablementChange(Highlighting highlighting, PropertyChangeEvent event) {
        Object value = event.getNewValue();
        boolean eventValue;
        if (value instanceof Boolean)
            eventValue = ((Boolean) value).booleanValue();
        else if (IPreferenceStore.TRUE.equals(value))
            eventValue = true;
        else
            eventValue = false;
        highlighting.setEnabled(eventValue);
    }

    private void adaptToTextForegroundChange(Highlighting highlighting, PropertyChangeEvent event) {
        RGB rgb = null;

        Object value = event.getNewValue();
        if (value instanceof RGB)
            rgb = (RGB) value;
        else if (value instanceof String)
            rgb = StringConverter.asRGB((String) value);

        if (rgb != null) {

            String property = event.getProperty();
            Color color = fColorManager.getColor(property);

            if ((color == null || !rgb.equals(color.getRGB())) && fColorManager instanceof IColorManagerExtension) {
                IColorManagerExtension ext = (IColorManagerExtension) fColorManager;
                ext.unbindColor(property);
                ext.bindColor(property, rgb);
                color = fColorManager.getColor(property);
            }

            TextAttribute oldAttr = highlighting.getTextAttribute();
            highlighting.setTextAttribute(new TextAttribute(color, oldAttr.getBackground(), oldAttr.getStyle()));
        }
    }

    private void adaptToTextStyleChange(Highlighting highlighting, PropertyChangeEvent event, int styleAttribute) {
        boolean eventValue = false;
        Object value = event.getNewValue();
        if (value instanceof Boolean)
            eventValue = ((Boolean) value).booleanValue();
        else if (IPreferenceStore.TRUE.equals(value))
            eventValue = true;

        TextAttribute oldAttr = highlighting.getTextAttribute();
        boolean activeValue = (oldAttr.getStyle() & styleAttribute) == styleAttribute;

        if (activeValue != eventValue)
            highlighting.setTextAttribute(new TextAttribute(oldAttr.getForeground(), oldAttr.getBackground(),
                    eventValue ? oldAttr.getStyle() | styleAttribute : oldAttr.getStyle() & ~styleAttribute));
    }

    private void addColor(String colorKey) {
        if (fColorManager != null && colorKey != null && fColorManager.getColor(colorKey) == null) {
            RGB rgb = PreferenceConverter.getColor(fPreferenceStore, colorKey);
            if (fColorManager instanceof IColorManagerExtension) {
                IColorManagerExtension ext = (IColorManagerExtension) fColorManager;
                ext.unbindColor(colorKey);
                ext.bindColor(colorKey, rgb);
            }
        }
    }

    private void removeColor(String colorKey) {
        if (fColorManager instanceof IColorManagerExtension)
            ((IColorManagerExtension) fColorManager).unbindColor(colorKey);
    }

    /**
     * Returns this hightlighter's reconciler.
     *
     * @return the semantic highlighter reconciler or <code>null</code> if none
     * @since 3.3
     */
    public SemanticHighlightingReconciler getReconciler() {
        return fReconciler;
    }
}