diff options
Diffstat (limited to 'core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/openon/OpenFileHyperlinkTracker.java')
-rw-r--r-- | core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/openon/OpenFileHyperlinkTracker.java | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/openon/OpenFileHyperlinkTracker.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/openon/OpenFileHyperlinkTracker.java new file mode 100644 index 0000000000..372a62008c --- /dev/null +++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/openon/OpenFileHyperlinkTracker.java @@ -0,0 +1,660 @@ +/******************************************************************************* + * 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); + } +} |