org.eclipse.wst.sse.ui.internal.openon.OpenFileHyperlinkTracker.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wst.sse.ui.internal.openon.OpenFileHyperlinkTracker.java

Source

/*******************************************************************************
 * Copyright (c) 2001, 2006 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
 *     Jens Lukowski/Innoopract - initial renaming/restructuring
 *     
 *******************************************************************************/
package org.eclipse.wst.sse.ui.internal.openon;

import com.ibm.icu.util.StringTokenizer;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.wst.sse.ui.internal.Logger;
import org.eclipse.wst.sse.ui.internal.util.EditorUtility;

/**
 * @deprecated Use org.eclipse.jface.text.hyperlink.HyperlinkManager
 */
public class OpenFileHyperlinkTracker implements KeyListener, MouseListener, MouseMoveListener, FocusListener,
        PaintListener, IPropertyChangeListener, IDocumentListener, ITextInputListener {

    /** The session is active. */
    private boolean fActive;

    /** The currently active style range. */
    private IRegion fActiveRegion;
    /** Preference key for browser-like links to be enabled */
    private String fBrowserLikeLinksKeyModifierKey;

    /** The link color. */
    private Color fColor;
    /** The hand cursor. */
    private Cursor fCursor;
    /** The key modifier mask. */
    private int fKeyModifierMask;
    /** Preference key for hyperlink underline color */
    private String fLinkColorKey;
    /** The preference store */
    private IPreferenceStore fPreferenceStore;
    /** The currently active style range as position. */
    private Position fRememberedPosition;

    /** The text viewer this hyperlink tracker is associated with */
    private ITextViewer fTextViewer;

    /**
     *  
     */
    public OpenFileHyperlinkTracker(ITextViewer textViewer) {
        fTextViewer = textViewer;
    }

    private void activateCursor(ITextViewer viewer) {
        StyledText text = viewer.getTextWidget();
        if (text == null || text.isDisposed())
            return;
        Display display = text.getDisplay();
        if (fCursor == null)
            fCursor = new Cursor(display, SWT.CURSOR_HAND);
        text.setCursor(fCursor);
    }

    private int computeStateMask(String modifiers) {
        if (modifiers == null)
            return -1;

        if (modifiers.length() == 0)
            return SWT.NONE;

        int stateMask = 0;
        StringTokenizer modifierTokenizer = new StringTokenizer(modifiers, ",;.:+-* "); //$NON-NLS-1$
        while (modifierTokenizer.hasMoreTokens()) {
            int modifier = EditorUtility.findLocalizedModifier(modifierTokenizer.nextToken());
            if (modifier == 0 || (stateMask & modifier) == modifier)
                return -1;
            stateMask = stateMask | modifier;
        }
        return stateMask;
    }

    /**
     * Creates a color from the information stored in the given preference
     * store. Returns <code>null</code> if there is no such information
     * available.
     */
    private 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);
        }

        return EditorUtility.getColor(rgb);
    }

    public void deactivate() {
        deactivate(false);
    }

    public void deactivate(boolean redrawAll) {
        if (!fActive)
            return;

        repairRepresentation(redrawAll);
        fActive = false;
    }

    /*
     * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
     */
    public void documentAboutToBeChanged(DocumentEvent event) {
        if (fActive && fActiveRegion != null) {
            fRememberedPosition = new Position(fActiveRegion.getOffset(), fActiveRegion.getLength());
            try {
                event.getDocument().addPosition(fRememberedPosition);
            } catch (BadLocationException x) {
                fRememberedPosition = null;
            }
        }
    }

    /*
     * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
     */
    public void documentChanged(DocumentEvent event) {
        if (fRememberedPosition != null) {
            if (!fRememberedPosition.isDeleted()) {

                event.getDocument().removePosition(fRememberedPosition);
                fActiveRegion = new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength());
                fRememberedPosition = null;

                ITextViewer viewer = getTextViewer();
                if (viewer != null) {
                    StyledText widget = viewer.getTextWidget();
                    if (widget != null && !widget.isDisposed()) {
                        widget.getDisplay().asyncExec(new Runnable() {
                            public void run() {
                                deactivate();
                            }
                        });
                    }
                }

            } else {
                fActiveRegion = null;
                fRememberedPosition = null;
                deactivate();
            }
        }
    }

    /*
     * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
     */
    public void focusGained(FocusEvent e) {
    }

    /*
     * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
     */
    public void focusLost(FocusEvent event) {
        deactivate();
    }

    private int getCurrentTextOffset() {
        try {
            StyledText text = getTextViewer().getTextWidget();
            if (text == null || text.isDisposed())
                return -1;

            Display display = text.getDisplay();
            Point absolutePosition = display.getCursorLocation();
            Point relativePosition = text.toControl(absolutePosition);

            int widgetOffset = text.getOffsetAtLocation(relativePosition);
            if (getTextViewer() instanceof ITextViewerExtension5) {
                ITextViewerExtension5 extension = (ITextViewerExtension5) getTextViewer();
                return extension.widgetOffset2ModelOffset(widgetOffset);
            } else {
                return widgetOffset + getTextViewer().getVisibleRegion().getOffset();
            }

        } catch (IllegalArgumentException e) {
            return -1;
        }
    }

    private Point getMaximumLocation(StyledText text, int offset, int length) {
        Point maxLocation = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE);

        for (int i = 0; i <= length; i++) {
            Point location = text.getLocationAtOffset(offset + i);

            if (location.x > maxLocation.x)
                maxLocation.x = location.x;
            if (location.y > maxLocation.y)
                maxLocation.y = location.y;
        }

        return maxLocation;
    }

    private Point getMinimumLocation(StyledText text, int offset, int length) {
        Point minLocation = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);

        for (int i = 0; i <= length; i++) {
            Point location = text.getLocationAtOffset(offset + i);

            if (location.x < minLocation.x)
                minLocation.x = location.x;
            if (location.y < minLocation.y)
                minLocation.y = location.y;
        }

        return minLocation;
    }

    private IPreferenceStore getNewPreferenceStore() {
        return fPreferenceStore;
    }

    private ITextViewer getTextViewer() {
        return fTextViewer;
    }

    private void highlightRegion(ITextViewer viewer, IRegion region) {

        if (region.equals(fActiveRegion))
            return;

        repairRepresentation();

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

        // Underline
        int offset = 0;
        int length = 0;
        if (viewer instanceof ITextViewerExtension5) {
            ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
            IRegion widgetRange = extension
                    .modelRange2WidgetRange(new Region(region.getOffset(), region.getLength()));
            if (widgetRange == null)
                return;

            offset = widgetRange.getOffset();
            length = widgetRange.getLength();

        } else {
            offset = region.getOffset() - viewer.getVisibleRegion().getOffset();
            length = region.getLength();
        }
        // need clearBackground to be true for paint event to be fired
        text.redrawRange(offset, length, true);

        fActiveRegion = region;
    }

    private boolean includes(IRegion region, IRegion position) {
        return position.getOffset() >= region.getOffset()
                && position.getOffset() + position.getLength() <= region.getOffset() + region.getLength();
    }

    /*
     * @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;
        deactivate();
        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);
    }

    public void install(IPreferenceStore store) {
        fPreferenceStore = store;
        ITextViewer textViewer = getTextViewer();
        if (textViewer == null)
            return;

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

        updateColor(textViewer);

        textViewer.addTextInputListener(this);

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

        text.addKeyListener(this);
        text.addMouseListener(this);
        text.addMouseMoveListener(this);
        text.addFocusListener(this);
        text.addPaintListener(this);

        updateKeyModifierMask();

        fPreferenceStore.addPropertyChangeListener(this);
    }

    /*
     * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
     */
    public void keyPressed(KeyEvent event) {

        if (fActive) {
            deactivate();
            return;
        }

        if (event.keyCode != fKeyModifierMask) {
            deactivate();
            return;
        }

        fActive = true;

        //         removed for #25871
        //
        //         ISourceViewer viewer= getSourceViewer();
        //         if (viewer == null)
        //            return;
        //         
        //         IRegion region= getCurrentTextRegion(viewer);
        //         if (region == null)
        //            return;
        //         
        //         highlightRegion(viewer, region);
        //         activateCursor(viewer);
    }

    /*
     * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
     */
    public void keyReleased(KeyEvent event) {

        if (!fActive)
            return;

        deactivate();
    }

    /*
     * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
     */
    public void mouseDoubleClick(MouseEvent e) {
    }

    /*
     * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
     */
    public void mouseDown(MouseEvent event) {

        if (!fActive)
            return;

        if (event.stateMask != fKeyModifierMask) {
            deactivate();
            return;
        }

        if (event.button != 1) {
            deactivate();
            return;
        }
    }

    /*
     * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
     */
    public void mouseMove(MouseEvent event) {

        if (event.widget instanceof Control && !((Control) event.widget).isFocusControl()) {
            deactivate();
            return;
        }

        if (!fActive) {
            if (event.stateMask != fKeyModifierMask)
                return;
            // modifier was already pressed
            fActive = true;
        }

        ITextViewer viewer = getTextViewer();
        if (viewer == null) {
            deactivate();
            return;
        }

        StyledText text = viewer.getTextWidget();
        if (text == null || text.isDisposed()) {
            deactivate();
            return;
        }

        if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != 0) {
            deactivate();
            return;
        }

        IRegion region = null;
        int offset = getCurrentTextOffset();
        IOpenOn openOn = OpenOnProvider.getInstance().getOpenOn(getTextViewer().getDocument(), offset);
        if (openOn != null) {
            region = openOn.getOpenOnRegion(getTextViewer().getDocument(), offset);
        }
        if (region == null || region.getLength() == 0) {
            repairRepresentation();
            return;
        }

        highlightRegion(viewer, region);
        activateCursor(viewer);
    }

    /*
     * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
     */
    public void mouseUp(MouseEvent e) {

        if (!fActive)
            return;

        if (e.button != 1) {
            deactivate();
            return;
        }

        boolean wasActive = fCursor != null;
        IRegion previousRegion = fActiveRegion;

        deactivate();

        if (wasActive) {
            IOpenOn openOn = OpenOnProvider.getInstance().getOpenOn(getTextViewer().getDocument(),
                    previousRegion.getOffset());
            if (openOn != null) {
                openOn.openOn(getTextViewer().getDocument(), previousRegion);
            }
        }
    }

    /*
     * @see PaintListener#paintControl(PaintEvent)
     */
    public void paintControl(PaintEvent event) {
        if (fActiveRegion == null)
            return;

        ITextViewer viewer = getTextViewer();
        if (viewer == null)
            return;

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

        int offset = 0;
        int length = 0;

        if (viewer instanceof ITextViewerExtension5) {

            ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
            IRegion widgetRange = extension.modelRange2WidgetRange(fActiveRegion);
            if (widgetRange == null)
                return;

            offset = widgetRange.getOffset();
            length = widgetRange.getLength();

        } else {

            IRegion region = viewer.getVisibleRegion();
            if (!includes(region, fActiveRegion))
                return;

            offset = fActiveRegion.getOffset() - region.getOffset();
            length = fActiveRegion.getLength();
        }

        // support for bidi
        Point minLocation = getMinimumLocation(text, offset, length);
        Point maxLocation = getMaximumLocation(text, offset, length);

        int x1 = minLocation.x;
        int x2 = minLocation.x + maxLocation.x - minLocation.x - 1;
        int y = minLocation.y + text.getLineHeight() - 1;

        GC gc = event.gc;
        if (fColor != null && !fColor.isDisposed())
            gc.setForeground(fColor);
        gc.drawLine(x1, y, x2, y);
    }

    /*
     * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent event) {
        if (event.getProperty().equals(fLinkColorKey)) {
            ITextViewer viewer = getTextViewer();
            if (viewer != null)
                updateColor(viewer);
        } else if (event.getProperty().equals(fBrowserLikeLinksKeyModifierKey)) {
            updateKeyModifierMask();
        }
    }

    private void repairRepresentation() {
        repairRepresentation(false);
    }

    private void repairRepresentation(boolean redrawAll) {

        if (fActiveRegion == null)
            return;

        int offset = fActiveRegion.getOffset();
        int length = fActiveRegion.getLength();
        fActiveRegion = null;

        ITextViewer viewer = getTextViewer();
        if (viewer != null) {

            resetCursor(viewer);

            // Remove underline
            if (viewer instanceof ITextViewerExtension5) {
                ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
                offset = extension.modelOffset2WidgetOffset(offset);
            } else {
                offset -= viewer.getVisibleRegion().getOffset();
            }
            try {
                StyledText text = viewer.getTextWidget();

                // need clearBackground to be true for paint event to be fired
                text.redrawRange(offset, length, true);
            } catch (IllegalArgumentException x) {
                Logger.logException(x);
            }
        }
    }

    private void resetCursor(ITextViewer viewer) {
        StyledText text = viewer.getTextWidget();
        if (text != null && !text.isDisposed())
            text.setCursor(null);

        if (fCursor != null) {
            fCursor.dispose();
            fCursor = null;
        }
    }

    public void setHyperlinkPreferenceKeys(String linkColorKey, String browserLikeLinksKeyModifierKey) {
        fLinkColorKey = linkColorKey;
        fBrowserLikeLinksKeyModifierKey = browserLikeLinksKeyModifierKey;
    }

    public void uninstall() {
        if (fCursor != null) {
            fCursor.dispose();
            fCursor = null;
        }

        ITextViewer textViewer = getTextViewer();
        if (textViewer == null)
            return;

        textViewer.removeTextInputListener(this);

        IDocument document = textViewer.getDocument();
        if (document != null)
            document.removeDocumentListener(this);

        IPreferenceStore preferenceStore = getNewPreferenceStore();
        if (preferenceStore != null)
            preferenceStore.removePropertyChangeListener(this);

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

        text.removeKeyListener(this);
        text.removeMouseListener(this);
        text.removeMouseMoveListener(this);
        text.removeFocusListener(this);
        text.removePaintListener(this);
    }

    private void updateColor(ITextViewer viewer) {
        StyledText text = viewer.getTextWidget();
        if (text == null || text.isDisposed())
            return;

        Display display = text.getDisplay();
        fColor = createColor(getNewPreferenceStore(), fLinkColorKey, display);
    }

    private void updateKeyModifierMask() {
        String modifiers = getNewPreferenceStore().getString(fBrowserLikeLinksKeyModifierKey);
        fKeyModifierMask = computeStateMask(modifiers);
    }
}