aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Elsemore2013-06-21 13:37:11 (EDT)
committerMatthias Sohn2013-06-24 19:10:09 (EDT)
commit0906cde57ce4ae4117151d96a2af82e0dc076593 (patch)
tree7c59289de4991161e3cd021cf65bdf71d9dae6ce
parentcfea8aa03dd0f397febd0eafe154ed6e5a30ed22 (diff)
downloadegit-0906cde57ce4ae4117151d96a2af82e0dc076593.zip
egit-0906cde57ce4ae4117151d96a2af82e0dc076593.tar.gz
egit-0906cde57ce4ae4117151d96a2af82e0dc076593.tar.bz2
Support Mylyn links in History View, Staging View and Commit Dialogrefs/changes/87/13987/4
In the history view, staging view and commit dialog commit message viewers, hook in to registered hyperlink detectors (such as Mylyn task link detector). Bug: 399398 Change-Id: Ia315def21fb8d66ed124034a2cb5102069eaf17d Signed-off-by: Stephen Elsemore <selsemore@collab.net> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java45
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java83
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java51
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java35
4 files changed, 206 insertions, 8 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java
index dadb7bb..b426c94 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIUtils.java
@@ -40,12 +40,18 @@ import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
@@ -58,6 +64,7 @@ import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Resource;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
@@ -684,6 +691,44 @@ public class UIUtils {
return showInSubMenu;
}
+ /**
+ * Use hyperlink detectors to find a text viewer's hyperlinks and return the
+ * style ranges to render them.
+ *
+ * @param textViewer
+ * @param hyperlinkDetectors
+ * @return the style ranges to render the detected hyperlinks
+ */
+ public static StyleRange[] getHyperlinkDetectorStyleRanges(
+ ITextViewer textViewer, IHyperlinkDetector[] hyperlinkDetectors) {
+ List<StyleRange> styleRangeList = new ArrayList<StyleRange>();
+ if (hyperlinkDetectors != null && hyperlinkDetectors.length > 0) {
+ for (int i = 0; i < textViewer.getTextWidget().getText().length(); i++) {
+ IRegion region = new Region(i, 0);
+ for (IHyperlinkDetector hyperLinkDetector : hyperlinkDetectors) {
+ IHyperlink[] hyperlinks = hyperLinkDetector
+ .detectHyperlinks(textViewer, region, true);
+ if (hyperlinks != null) {
+ for (IHyperlink hyperlink : hyperlinks) {
+ StyleRange hyperlinkStyleRange = new StyleRange(
+ hyperlink.getHyperlinkRegion().getOffset(),
+ hyperlink.getHyperlinkRegion().getLength(),
+ Display.getDefault().getSystemColor(
+ SWT.COLOR_BLUE), Display
+ .getDefault().getSystemColor(
+ SWT.COLOR_WHITE));
+ hyperlinkStyleRange.underline = true;
+ styleRangeList.add(hyperlinkStyleRange);
+ }
+ }
+ }
+ }
+ }
+ StyleRange[] styleRangeArray = new StyleRange[styleRangeList.size()];
+ styleRangeList.toArray(styleRangeArray);
+ return styleRangeArray;
+ }
+
private static String getShowInMenuLabel() {
IBindingService bindingService = (IBindingService) PlatformUI
.getWorkbench().getAdapter(IBindingService.class);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java
index ab6f08f..651316b 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java
@@ -51,6 +51,9 @@ import org.eclipse.jface.text.TextEvent;
import org.eclipse.jface.text.WhitespaceCharacterPainter;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
+import org.eclipse.jface.text.hyperlink.MultipleHyperlinkPresenter;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.reconciler.IReconciler;
@@ -69,11 +72,13 @@ import org.eclipse.jgit.util.IntList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BidiSegmentEvent;
import org.eclipse.swt.custom.BidiSegmentListener;
+import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
@@ -81,7 +86,9 @@ import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.ActiveShellExpression;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.PlatformUI;
@@ -104,6 +111,11 @@ public class SpellcheckableMessageArea extends Composite {
static final int MAX_LINE_WIDTH = 72;
+ private static final Cursor SYS_LINK_CURSOR = PlatformUI.getWorkbench()
+ .getDisplay().getSystemCursor(SWT.CURSOR_HAND);
+
+ private final Cursor sys_normalCursor;
+
private static class TextViewerAction extends Action implements IUpdate {
private int fOperationCode= -1;
@@ -212,6 +224,8 @@ public class SpellcheckableMessageArea extends Composite {
private final SourceViewer sourceViewer;
+ private TextSourceViewerConfiguration configuration;
+
private BidiSegmentListener hardWrapSegmentListener;
// XXX: workaround for https://bugs.eclipse.org/400727
@@ -257,6 +271,7 @@ public class SpellcheckableMessageArea extends Composite {
getTextWidget().setFont(UIUtils
.getFont(UIPreferences.THEME_CommitMessageEditorFont));
+ sys_normalCursor = sourceViewer.getTextWidget().getCursor();
int endSpacing = 2;
int textWidth = getCharWidth() * MAX_LINE_WIDTH + endSpacing;
int textHeight = getLineHeight() * 7;
@@ -293,14 +308,38 @@ public class SpellcheckableMessageArea extends Composite {
Document document = new Document(initialText);
- sourceViewer.configure(new TextSourceViewerConfiguration(EditorsUI
+ configuration = new TextSourceViewerConfiguration(
+ EditorsUI
.getPreferenceStore()) {
+ public int getHyperlinkStateMask(ISourceViewer targetViewer) {
+ return SWT.NONE;
+ }
+
protected Map getHyperlinkDetectorTargets(ISourceViewer targetViewer) {
return getHyperlinkTargets();
}
@Override
+ public IHyperlinkPresenter getHyperlinkPresenter(
+ ISourceViewer targetViewer) {
+ return new MultipleHyperlinkPresenter(PlatformUI.getWorkbench()
+ .getDisplay().getSystemColor(SWT.COLOR_BLUE).getRGB()) {
+
+ @Override
+ public void hideHyperlinks() {
+ // We want links to always show.
+ }
+
+ };
+ }
+
+ public IHyperlinkDetector[] getHyperlinkDetectors(
+ ISourceViewer targetViewer) {
+ return getRegisteredHyperlinkDetectors(sourceViewer);
+ }
+
+ @Override
public IReconciler getReconciler(ISourceViewer viewer) {
if (!isEditable(viewer))
return null;
@@ -317,9 +356,16 @@ public class SpellcheckableMessageArea extends Composite {
return assistant;
}
- });
+ };
+
+ sourceViewer.configure(configuration);
sourceViewer.setDocument(document, annotationModel);
+ for (StyleRange styleRange : UIUtils
+ .getHyperlinkDetectorStyleRanges(sourceViewer,
+ configuration.getHyperlinkDetectors(sourceViewer)))
+ sourceViewer.getTextWidget().setStyleRange(styleRange);
+
configureContextMenu();
getTextWidget().addDisposeListener(new DisposeListener() {
@@ -634,6 +680,14 @@ public class SpellcheckableMessageArea extends Composite {
sourceViewer.addTextListener(new ITextListener() {
public void textChanged(TextEvent event) {
+ textWidget.setStyleRanges(
+ new StyleRange[0]);
+ for (StyleRange styleRange : UIUtils
+ .getHyperlinkDetectorStyleRanges(
+ sourceViewer,
+ configuration
+ .getHyperlinkDetectors(sourceViewer)))
+ textWidget.setStyleRange(styleRange);
if (undoAction != null)
undoAction.update();
if (redoAction != null)
@@ -641,6 +695,17 @@ public class SpellcheckableMessageArea extends Composite {
}
});
+ // set the cursor when hovering over a link
+ textWidget.addListener(SWT.MouseMove, new Listener() {
+ public void handleEvent(final Event e) {
+ StyleRange styleRange = getStyleRange(e.x, e.y);
+ if (styleRange != null && styleRange.underline)
+ textWidget.setCursor(SYS_LINK_CURSOR);
+ else
+ textWidget.setCursor(sys_normalCursor);
+ }
+ });
+
textWidget.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent disposeEvent) {
showWhitespaceAction.dispose();
@@ -648,6 +713,20 @@ public class SpellcheckableMessageArea extends Composite {
});
}
+ private StyleRange getStyleRange(final int x, final int y) {
+ final StyledText t = sourceViewer.getTextWidget();
+ final int offset;
+ try {
+ offset = t.getOffsetAtLocation(new Point(x, y));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ if (offset < t.getCharCount())
+ return t.getStyleRangeAtOffset(offset);
+ else
+ return null;
+ }
+
private void addProposals(final SubMenuManager quickFixMenu) {
IAnnotationModel sourceModel = sourceViewer.getAnnotationModel();
Iterator annotationIterator = sourceModel.getAnnotationIterator();
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
index f44e5a4..ffbe570 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitMessageViewer.java
@@ -14,6 +14,8 @@ package org.eclipse.egit.ui.internal.history;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
import org.eclipse.core.runtime.ListenerList;
@@ -34,7 +36,7 @@ import org.eclipse.jface.text.DefaultTextDoubleClickStrategy;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextOperationTarget;
-import org.eclipse.jface.text.TextViewer;
+import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
@@ -69,7 +71,7 @@ import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
-class CommitMessageViewer extends TextViewer implements
+class CommitMessageViewer extends SourceViewer implements
ISelectionChangedListener {
private static final Color SYS_LINKCOLOR = PlatformUI.getWorkbench()
@@ -118,8 +120,10 @@ class CommitMessageViewer extends TextViewer implements
private ListenerHandle refsChangedListener;
+ private StyleRange[] styleRanges;
+
CommitMessageViewer(final Composite parent, final IPageSite site, IWorkbenchPartSite partSite) {
- super(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.READ_ONLY);
+ super(parent, null, SWT.H_SCROLL | SWT.V_SCROLL | SWT.READ_ONLY);
this.partSite = partSite;
final StyledText t = getTextWidget();
@@ -130,10 +134,13 @@ class CommitMessageViewer extends TextViewer implements
// set the cursor when hovering over a link
t.addListener(SWT.MouseMove, new Listener() {
public void handleEvent(final Event e) {
- if (getStyleRange(e.x, e.y) instanceof ObjectLink)
+ StyleRange styleRange = getStyleRange(e.x, e.y);
+ if (styleRange != null && styleRange.underline)
t.setCursor(SYS_LINK_CURSOR);
else
t.setCursor(sys_normalCursor);
+ for (StyleRange sr : styleRanges)
+ getTextWidget().setStyleRange(sr);
}
});
// react on link click
@@ -272,10 +279,42 @@ class CommitMessageViewer extends TextViewer implements
public void run() {
if (text.isDisposed())
return;
+
setDocument(new Document(job.getFormatResult()
.getCommitInfo()));
- text.setStyleRanges(job.getFormatResult()
- .getStyleRange());
+
+ // Combine the style ranges from the format job and the
+ // style ranges for hyperlinks found by registered
+ // hyperlink detectors.
+ List<StyleRange> styleRangeList = new ArrayList<StyleRange>();
+ for (StyleRange styleRange : job.getFormatResult()
+ .getStyleRange())
+ styleRangeList.add(styleRange);
+
+ StyleRange[] hyperlinkDetectorStyleRanges = UIUtils
+ .getHyperlinkDetectorStyleRanges(
+ CommitMessageViewer.this,
+ fHyperlinkDetectors);
+ for (StyleRange styleRange : hyperlinkDetectorStyleRanges)
+ styleRangeList.add(styleRange);
+
+ styleRanges = new StyleRange[styleRangeList.size()];
+ styleRangeList.toArray(styleRanges);
+
+ // Style ranges must be in order.
+ Arrays.sort(styleRanges, new Comparator<StyleRange>() {
+ public int compare(StyleRange o1, StyleRange o2) {
+ if (o2.start > o1.start)
+ return -1;
+ if (o1.start > o2.start)
+ return 1;
+ return 0;
+ }
+ });
+
+ text.setStyleRanges(new StyleRange[0]);
+ for (StyleRange sr : styleRanges)
+ text.setStyleRange(sr);
}
});
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
index b6e99b1..a6bd737 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
@@ -59,6 +59,10 @@ import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
+import org.eclipse.jface.text.hyperlink.MultipleHyperlinkPresenter;
+import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
@@ -117,6 +121,8 @@ import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
@@ -780,6 +786,35 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener,
revInfoSplit = new SashForm(graphDetailSplit, SWT.HORIZONTAL);
commentViewer = new CommitMessageViewer(revInfoSplit, getSite(), getPartSite());
+
+ TextSourceViewerConfiguration configuration = new TextSourceViewerConfiguration(
+ EditorsUI.getPreferenceStore()) {
+
+ public int getHyperlinkStateMask(ISourceViewer sourceViewer) {
+ return SWT.NONE;
+ }
+
+ @Override
+ public IHyperlinkPresenter getHyperlinkPresenter(
+ ISourceViewer sourceViewer) {
+ return new MultipleHyperlinkPresenter(PlatformUI.getWorkbench()
+ .getDisplay().getSystemColor(SWT.COLOR_BLUE).getRGB()) {
+
+ @Override
+ public void hideHyperlinks() {
+ // We want links to always show.
+ }
+
+ };
+ }
+
+ public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
+ return getRegisteredHyperlinkDetectors(sourceViewer);
+ }
+ };
+
+ commentViewer.configure(configuration);
+
fileViewer = new CommitFileDiffViewer(revInfoSplit, getSite());
findToolbar = new FindToolbar(historyControl);