Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/hyperlink/HighlighterHyperlinkPresenter.java')
-rw-r--r--core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/hyperlink/HighlighterHyperlinkPresenter.java478
1 files changed, 478 insertions, 0 deletions
diff --git a/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/hyperlink/HighlighterHyperlinkPresenter.java b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/hyperlink/HighlighterHyperlinkPresenter.java
new file mode 100644
index 0000000000..60a35f43f8
--- /dev/null
+++ b/core/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/hyperlink/HighlighterHyperlinkPresenter.java
@@ -0,0 +1,478 @@
+/*******************************************************************************
+ * Copyright (c) 2005 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 org.eclipse.wst.sse.ui.internal.hyperlink;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.text.Assert;
+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.ITextViewerExtension2;
+import org.eclipse.jface.text.ITextViewerExtension5;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
+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.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.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+
+
+/**
+ * The is almost an exact copy of DefaultHyperlinkPresenter. However this
+ * hyperlink presenter works with the StructuredTextEditor's Highlighter
+ * instead of TextPresentation.
+ *
+ * The main difference is <code>text.redrawRange(offset, length, true);</code>
+ * is called instead of passing false for clearBackground. Also all mention of
+ * TextPresentation was removed since it does not really apply.
+ *
+ * @see org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter
+ */
+public class HighlighterHyperlinkPresenter implements IHyperlinkPresenter, PaintListener, ITextInputListener, IDocumentListener, IPropertyChangeListener {
+
+ /**
+ * A named preference that holds the color used for hyperlinks.
+ * <p>
+ * Value is of type <code>String</code>. A RGB color value encoded as a
+ * string using class <code>PreferenceConverter</code>
+ * </p>
+ *
+ * @see org.eclipse.jface.resource.StringConverter
+ * @see org.eclipse.jface.preference.PreferenceConverter
+ */
+ public final static String HYPERLINK_COLOR = "hyperlinkColor"; //$NON-NLS-1$
+
+
+ /** The text viewer. */
+ private ITextViewer fTextViewer;
+ /** The hand cursor. */
+ private Cursor fCursor;
+ /** The link color. */
+ private Color fColor;
+ /** Tells whether to dispose the color on uninstall. */
+ private boolean fDisposeColor;
+ /** The currently active region. */
+ private IRegion fActiveRegion;
+ /** The currently active style range as position. */
+ private Position fRememberedPosition;
+ /** The optional preference store */
+ private IPreferenceStore fPreferenceStore;
+
+
+ /**
+ * Creates a new default hyperlink presenter which uses
+ * {@link #HYPERLINK_COLOR}to read the color from the given preference
+ * store.
+ *
+ * @param store
+ * the preference store
+ */
+ public HighlighterHyperlinkPresenter(IPreferenceStore store) {
+ fPreferenceStore = store;
+ fDisposeColor = true;
+ }
+
+ /**
+ * Creates a new default hyperlink presenter.
+ *
+ * @param color
+ * the hyperlink color, to be disposed by the caller
+ */
+ public HighlighterHyperlinkPresenter(Color color) {
+ fDisposeColor = false;
+ fColor = color;
+ }
+
+ public boolean canShowMultipleHyperlinks() {
+ return false;
+ }
+
+ public void showHyperlinks(IHyperlink[] hyperlinks) {
+ Assert.isLegal(hyperlinks != null && hyperlinks.length == 1);
+ highlightRegion(hyperlinks[0].getHyperlinkRegion());
+ activateCursor();
+ }
+
+ public void hideHyperlinks() {
+ repairRepresentation();
+ fRememberedPosition = null;
+ }
+
+ public void install(ITextViewer textViewer) {
+ Assert.isNotNull(textViewer);
+ fTextViewer = textViewer;
+ fTextViewer.addTextInputListener(this);
+
+ StyledText text = fTextViewer.getTextWidget();
+ if (text != null && !text.isDisposed()) {
+ text.addPaintListener(this);
+ if (fPreferenceStore != null)
+ fColor = createColor(fPreferenceStore, HYPERLINK_COLOR, text.getDisplay());
+ }
+
+ if (fPreferenceStore != null)
+ fPreferenceStore.addPropertyChangeListener(this);
+ }
+
+ public void uninstall() {
+ fTextViewer.removeTextInputListener(this);
+
+ if (fColor != null) {
+ if (fDisposeColor)
+ fColor.dispose();
+ fColor = null;
+ }
+
+ if (fCursor != null) {
+ fCursor.dispose();
+ fCursor = null;
+ }
+
+ StyledText text = fTextViewer.getTextWidget();
+ if (text != null && !text.isDisposed())
+ text.removePaintListener(this);
+
+ fTextViewer = null;
+
+ if (fPreferenceStore != null)
+ fPreferenceStore.removePropertyChangeListener(this);
+ }
+
+ public void setColor(Color color) {
+ Assert.isNotNull(fTextViewer);
+ fColor = color;
+ }
+
+ private void highlightRegion(IRegion region) {
+
+ if (region.equals(fActiveRegion))
+ return;
+
+ repairRepresentation();
+
+ StyledText text = fTextViewer.getTextWidget();
+ if (text == null || text.isDisposed())
+ return;
+
+
+ // Underline
+ int offset = 0;
+ int length = 0;
+ if (fTextViewer instanceof ITextViewerExtension5) {
+ ITextViewerExtension5 extension = (ITextViewerExtension5) fTextViewer;
+ IRegion widgetRange = extension.modelRange2WidgetRange(region);
+ if (widgetRange == null)
+ return;
+
+ offset = widgetRange.getOffset();
+ length = widgetRange.getLength();
+
+ }
+ else {
+ offset = region.getOffset() - fTextViewer.getVisibleRegion().getOffset();
+ length = region.getLength();
+ }
+
+ // needs to clean background due to StructuredTextEditor's highlighter
+ text.redrawRange(offset, length, true);
+
+ // Invalidate region ==> apply text presentation
+ fActiveRegion = region;
+
+ if (fTextViewer instanceof ITextViewerExtension2)
+ ((ITextViewerExtension2) fTextViewer).invalidateTextPresentation(region.getOffset(), region.getLength());
+ else
+ fTextViewer.invalidateTextPresentation();
+ }
+
+ private void activateCursor() {
+ StyledText text = fTextViewer.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 void resetCursor() {
+ StyledText text = fTextViewer.getTextWidget();
+ if (text != null && !text.isDisposed())
+ text.setCursor(null);
+
+ if (fCursor != null) {
+ fCursor.dispose();
+ fCursor = null;
+ }
+ }
+
+ private void repairRepresentation() {
+
+ if (fActiveRegion == null)
+ return;
+
+ int offset = fActiveRegion.getOffset();
+ int length = fActiveRegion.getLength();
+ fActiveRegion = null;
+
+ resetCursor();
+
+ // Invalidate ==> remove applied text presentation
+ if (fTextViewer instanceof ITextViewerExtension2)
+ ((ITextViewerExtension2) fTextViewer).invalidateTextPresentation(offset, length);
+ else
+ fTextViewer.invalidateTextPresentation();
+
+ // Remove underline
+ if (fTextViewer instanceof ITextViewerExtension5) {
+ ITextViewerExtension5 extension = (ITextViewerExtension5) fTextViewer;
+ offset = extension.modelOffset2WidgetOffset(offset);
+ }
+ else {
+ offset -= fTextViewer.getVisibleRegion().getOffset();
+ }
+ try {
+ StyledText text = fTextViewer.getTextWidget();
+
+ // needs to clean background due to StructuredTextEditor's
+ // highlighter
+ text.redrawRange(offset, length, true);
+
+ }
+ catch (IllegalArgumentException x) {
+ // ignore - do not log
+ }
+ }
+
+ /*
+ * @see PaintListener#paintControl(PaintEvent)
+ */
+ public void paintControl(PaintEvent event) {
+ if (fActiveRegion == null)
+ return;
+
+ StyledText text = fTextViewer.getTextWidget();
+ if (text == null || text.isDisposed())
+ return;
+
+ int offset = 0;
+ int length = 0;
+
+ if (fTextViewer instanceof ITextViewerExtension5) {
+
+ ITextViewerExtension5 extension = (ITextViewerExtension5) fTextViewer;
+ IRegion widgetRange = extension.modelRange2WidgetRange(fActiveRegion);
+ if (widgetRange == null)
+ return;
+
+ offset = widgetRange.getOffset();
+ length = widgetRange.getLength();
+
+ }
+ else {
+
+ IRegion region = fTextViewer.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 = maxLocation.x - 1;
+ int y = minLocation.y + text.getLineHeight() - 1;
+
+ GC gc = event.gc;
+ if (fColor != null && !fColor.isDisposed())
+ gc.setForeground(fColor);
+ else if (fColor == null && !(offset < 0 && offset >= text.getCharCount())) {
+ StyleRange style = text.getStyleRangeAtOffset(offset);
+ if (style != null)
+ gc.setForeground(style.foreground);
+ }
+ gc.drawLine(x1, y, x2, y);
+ }
+
+ private Point getMinimumLocation(StyledText text, int offset, int length) {
+ int max = text.getCharCount();
+ Rectangle bounds = text.getBounds();
+ Point minLocation = new Point(bounds.width, bounds.height);
+ for (int i = 0; i <= length; i++) {
+ int k = offset + i;
+ if (k < 0 || k > max)
+ break;
+
+ Point location = text.getLocationAtOffset(k);
+ if (location.x < minLocation.x)
+ minLocation.x = location.x;
+ if (location.y < minLocation.y)
+ minLocation.y = location.y;
+ }
+
+ return minLocation;
+ }
+
+ private Point getMaximumLocation(StyledText text, int offset, int length) {
+ Point maxLocation = new Point(0, 0);
+
+ for (int i = 0; i <= length; i++) {
+ int k = offset + i;
+ if (k < 0 || k > text.getCharCount())
+ break;
+
+ Point location = text.getLocationAtOffset(k);
+ if (location.x > maxLocation.x)
+ maxLocation.x = location.x;
+ if (location.y > maxLocation.y)
+ maxLocation.y = location.y;
+ }
+
+ return maxLocation;
+ }
+
+ 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.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
+ */
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ if (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;
+
+ StyledText widget = fTextViewer.getTextWidget();
+ if (widget != null && !widget.isDisposed()) {
+ widget.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ hideHyperlinks();
+ }
+ });
+ }
+
+ }
+ else {
+ fActiveRegion = null;
+ fRememberedPosition = null;
+ hideHyperlinks();
+ }
+ }
+ }
+
+ /*
+ * @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;
+ hideHyperlinks();
+ 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);
+ }
+
+ /**
+ * Creates a color from the information stored in the given preference
+ * store.
+ *
+ * @param store
+ * the preference store
+ * @param key
+ * the key
+ * @param display
+ * the display
+ * @return the color or <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);
+
+ if (rgb != null)
+ return new Color(display, rgb);
+ }
+
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+ if (!HYPERLINK_COLOR.equals(event.getProperty()))
+ return;
+
+ if (fDisposeColor && fColor != null && !fColor.isDisposed())
+ fColor.dispose();
+ fColor = null;
+
+ StyledText textWidget = fTextViewer.getTextWidget();
+ if (textWidget != null && !textWidget.isDisposed())
+ fColor = createColor(fPreferenceStore, HYPERLINK_COLOR, textWidget.getDisplay());
+ }
+}

Back to the top