aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Elsemore2013-06-21 13:37:11 -0400
committerMatthias Sohn2013-06-24 19:10:09 -0400
commit0906cde57ce4ae4117151d96a2af82e0dc076593 (patch)
tree7c59289de4991161e3cd021cf65bdf71d9dae6ce
parentcfea8aa03dd0f397febd0eafe154ed6e5a30ed22 (diff)
downloadegit-0906cde57ce4ae4117151d96a2af82e0dc076593.zip
egit-0906cde57ce4ae4117151d96a2af82e0dc076593.tar.gz
egit-0906cde57ce4ae4117151d96a2af82e0dc076593.tar.xz
Support Mylyn links in History View, Staging View and Commit Dialog
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);