summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Wagenknecht2013-12-04 13:46:56 (EST)
committer Gunnar Wagenknecht2013-12-19 09:00:47 (EST)
commite9119ebffe7d2e51af6ce1420fe9c24c7d663fc0 (patch)
tree954001b58a7e231fd95473f4d31bcf6609294f36
parent491b21b47b52bdcdc34830d42661db517b5f7791 (diff)
downloadorg.eclipse.mylyn.reviews-e9119ebffe7d2e51af6ce1420fe9c24c7d663fc0.zip
org.eclipse.mylyn.reviews-e9119ebffe7d2e51af6ce1420fe9c24c7d663fc0.tar.gz
org.eclipse.mylyn.reviews-e9119ebffe7d2e51af6ce1420fe9c24c7d663fc0.tar.bz2
422673: Add comments navigation in compare view.refs/changes/27/19327/7
This commit adds two buttons to the compare viewer when comparing review patch sets. Both buttons trigger the execution of a specific command. Two new commands have been introduced for processing of the actions. Change-Id: I4d6e8018bfec1a11ec50012fd2b99cb30ee1c10f Also-by: Guy Perron <guy.perron@ericsson.com> Signed-off-by: Guy Perron <guy.perron@ericsson.com> Signed-off-by: Gunnar Wagenknecht <gunnar@wagenknecht.org> Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=422673
-rw-r--r--org.eclipse.mylyn.reviews.ui/icons/elcl16/nxtanmly_menu.pngbin0 -> 402 bytes
-rw-r--r--org.eclipse.mylyn.reviews.ui/icons/elcl16/prevanmly_menu.pngbin0 -> 442 bytes
-rw-r--r--org.eclipse.mylyn.reviews.ui/plugin.xml13
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/Messages.java8
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsImages.java4
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/annotations/ReviewAnnotationModel.java6
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/Direction.java32
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/GotoCommentHandler.java35
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewCompareAnnotationSupport.java243
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewItemCompareEditorInput.java79
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/messages.properties9
11 files changed, 367 insertions, 62 deletions
diff --git a/org.eclipse.mylyn.reviews.ui/icons/elcl16/nxtanmly_menu.png b/org.eclipse.mylyn.reviews.ui/icons/elcl16/nxtanmly_menu.png
new file mode 100644
index 0000000..48c8f7a
--- /dev/null
+++ b/org.eclipse.mylyn.reviews.ui/icons/elcl16/nxtanmly_menu.png
Binary files differ
diff --git a/org.eclipse.mylyn.reviews.ui/icons/elcl16/prevanmly_menu.png b/org.eclipse.mylyn.reviews.ui/icons/elcl16/prevanmly_menu.png
new file mode 100644
index 0000000..cdfb421
--- /dev/null
+++ b/org.eclipse.mylyn.reviews.ui/icons/elcl16/prevanmly_menu.png
Binary files differ
diff --git a/org.eclipse.mylyn.reviews.ui/plugin.xml b/org.eclipse.mylyn.reviews.ui/plugin.xml
index 8f7f632..b71d196 100644
--- a/org.eclipse.mylyn.reviews.ui/plugin.xml
+++ b/org.eclipse.mylyn.reviews.ui/plugin.xml
@@ -115,6 +115,19 @@
visibleInUI="true">
</commonFilter>
</extension>
+ <extension
+ point="org.eclipse.ui.commands">
+ <command
+ description="Navigates to the next comment annotation in the compare editor when comparing review patch sets."
+ id="org.eclipse.mylyn.reviews.ui.commands.navigate.comment.next"
+ name="Next Comment">
+ </command>
+ <command
+ description="Navigates to the previous comment annotation in the compare editor when comparing review patch sets."
+ id="org.eclipse.mylyn.reviews.ui.commands.navigate.comment.previous"
+ name="Previous Comment">
+ </command>
+ </extension>
<!--
<extension point="org.eclipse.ui.workbench.texteditor.rulerColumns">
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/Messages.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/Messages.java
index b31a781..ad2f664 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/Messages.java
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/Messages.java
@@ -28,6 +28,14 @@ public class Messages extends NLS {
public static String Reviews_UpdateFailure;
+ public static String Reviews_NextComment;
+
+ public static String Reviews_NextComment_Tooltip;
+
+ public static String Reviews_PreviousComment;
+
+ public static String Reviews_PreviousComment_Tooltip;
+
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsImages.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsImages.java
index fca6ac7..497c528 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsImages.java
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsImages.java
@@ -61,6 +61,10 @@ public class ReviewsImages {
public static final ImageDescriptor BLANK = create("obj12/blank.gif"); //$NON-NLS-1$
+ public static final ImageDescriptor NEXT_COMMENT = create("elcl16/nxtanmly_menu.png"); //$NON-NLS-1$
+
+ public static final ImageDescriptor PREVIOUS_COMMENT = create("elcl16/prevanmly_menu.png"); //$NON-NLS-1$
+
private static ImageDescriptor create(String path) {
try {
return ImageDescriptor.createFromURL(makeIconFileURL(path));
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/annotations/ReviewAnnotationModel.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/annotations/ReviewAnnotationModel.java
index de52b50..baebb6a 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/annotations/ReviewAnnotationModel.java
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/annotations/ReviewAnnotationModel.java
@@ -35,10 +35,10 @@ import org.eclipse.jface.text.source.IAnnotationModelListener;
import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.reviews.ui.ReviewsUiPlugin;
+import org.eclipse.mylyn.reviews.core.model.IComment;
import org.eclipse.mylyn.reviews.core.model.ILineLocation;
import org.eclipse.mylyn.reviews.core.model.ILocation;
import org.eclipse.mylyn.reviews.core.model.IReviewItem;
-import org.eclipse.mylyn.reviews.core.model.IComment;
import org.eclipse.mylyn.reviews.ui.ReviewBehavior;
/**
@@ -153,6 +153,10 @@ public class ReviewAnnotationModel implements IAnnotationModel {
return behavior;
}
+ public IDocument getDocument() {
+ return document;
+ }
+
/**
* Returns the first annotation that this knows about for the given offset in the document
*/
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/Direction.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/Direction.java
new file mode 100644
index 0000000..7cc1e45
--- /dev/null
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/Direction.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.reviews.ui.compare;
+
+public enum Direction {
+
+ FORWARDS(true), BACKWARDS(false);
+
+ private final boolean forward;
+
+ private Direction(boolean forward) {
+ this.forward = forward;
+
+ }
+
+ public boolean isForwards() {
+ return forward;
+ }
+
+ public boolean isBackwards() {
+ return !forward;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/GotoCommentHandler.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/GotoCommentHandler.java
new file mode 100644
index 0000000..635255c
--- /dev/null
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/GotoCommentHandler.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.reviews.ui.compare;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+
+final class GotoCommentHandler extends AbstractHandler {
+ private final Direction direction;
+
+ private final ReviewCompareAnnotationSupport support;
+
+ GotoCommentHandler(Direction direction, ReviewCompareAnnotationSupport support) {
+ this.direction = direction;
+ this.support = support;
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ support.gotoAnnotation(direction);
+
+ // ignore
+ return null;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewCompareAnnotationSupport.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewCompareAnnotationSupport.java
index 5ad50b2..35f5172 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewCompareAnnotationSupport.java
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewCompareAnnotationSupport.java
@@ -7,24 +7,36 @@
*
* Contributors:
* Atlassian - initial API and implementation
+ * Tasktop Technologies - cleanup and support for gotoAnnotation
******************************************************************************/
package org.eclipse.mylyn.internal.reviews.ui.compare;
import java.lang.reflect.Field;
+import java.util.Iterator;
import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
import org.eclipse.compare.internal.MergeSourceViewer;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITextViewerExtension5;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.reviews.ui.ReviewsUiPlugin;
+import org.eclipse.mylyn.internal.reviews.ui.annotations.CommentAnnotation;
import org.eclipse.mylyn.internal.reviews.ui.annotations.ReviewAnnotationModel;
import org.eclipse.mylyn.reviews.core.model.IFileItem;
import org.eclipse.mylyn.reviews.ui.ReviewBehavior;
+import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.texteditor.AbstractTextEditor;
/**
* Manages annotation models for compare viewers.
@@ -56,55 +68,16 @@ public class ReviewCompareAnnotationSupport {
private ReviewCompareInputListener rightViewerListener;
+ private MergeSourceViewer leftSourceViewer;
+
+ private MergeSourceViewer rightSourceViewer;
+
public ReviewCompareAnnotationSupport(Viewer contentViewer) {
this.leftAnnotationModel = new ReviewAnnotationModel();
this.rightAnnotationModel = new ReviewAnnotationModel();
install(contentViewer);
}
- public void attachToViewer(final TextMergeViewer viewer, final MergeSourceViewer fLeft,
- final MergeSourceViewer fRight) {
- // only create listeners if they are not already existing
- if (!isListenerFor(leftViewerListener, fLeft, leftAnnotationModel)) {
- leftViewerListener = registerInputListener(fLeft, leftAnnotationModel);
- } else {
- /*
- * Using asyncExec here because if the underlying slaveDocument (part of the file that gets displayed when clicking
- * on a java structure in the compare editor) is changed, but the master document is not, we do not get any event
- * afterwards that would give us a place to hook our code to override the annotationHover. Since all is done in the
- * UI thread, using this asyncExec hack works because the unconfigure and configure of the document is finished and
- * our hover-hack stays.
- */
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- try {
- // if listeners exist, just make sure the hover hack is in there
- leftViewerListener.forceCustomAnnotationHover();
- } catch (Exception e) {
- StatusHandler.log(new Status(IStatus.ERROR, ReviewsUiPlugin.PLUGIN_ID,
- "Error attaching annotation hover", e));
- }
- }
- });
- }
-
- if (!isListenerFor(rightViewerListener, fRight, rightAnnotationModel)) {
- rightViewerListener = registerInputListener(fRight, rightAnnotationModel);
- } else {
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- try {
- // if listeners exist, just make sure the hover hack is in there
- rightViewerListener.forceCustomAnnotationHover();
- } catch (Exception e) {
- StatusHandler.log(new Status(IStatus.ERROR, ReviewsUiPlugin.PLUGIN_ID,
- "Error attaching annotation hover", e));
- }
- }
- });
- }
- }
-
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -153,19 +126,16 @@ public class ReviewCompareAnnotationSupport {
TextMergeViewer textMergeViewer = (TextMergeViewer) contentViewer;
try {
Class<TextMergeViewer> clazz = TextMergeViewer.class;
- Field declaredField = clazz.getDeclaredField("fLeft");
+ Field declaredField = clazz.getDeclaredField("fLeft"); //$NON-NLS-1$
declaredField.setAccessible(true);
- final MergeSourceViewer fLeft = (MergeSourceViewer) declaredField.get(textMergeViewer);
+ leftSourceViewer = (MergeSourceViewer) declaredField.get(textMergeViewer);
- declaredField = clazz.getDeclaredField("fRight");
+ declaredField = clazz.getDeclaredField("fRight"); //$NON-NLS-1$
declaredField.setAccessible(true);
- final MergeSourceViewer fRight = (MergeSourceViewer) declaredField.get(textMergeViewer);
+ rightSourceViewer = (MergeSourceViewer) declaredField.get(textMergeViewer);
- leftViewerListener = registerInputListener(fLeft, leftAnnotationModel);
- rightViewerListener = registerInputListener(fRight, rightAnnotationModel);
- //attachToViewer(textMergeViewer, fLeft, fRight);
-
- //configureSourceViewers(contentViewer, textMergeViewer, fLeft, fRight);
+ leftViewerListener = registerInputListener(leftSourceViewer, leftAnnotationModel);
+ rightViewerListener = registerInputListener(rightSourceViewer, rightAnnotationModel);
} catch (Throwable t) {
StatusHandler.log(new Status(IStatus.WARNING, ReviewsUiPlugin.PLUGIN_ID,
"Could not initialize annotation model for " + Viewer.class.getName(), t)); //$NON-NLS-1$
@@ -173,6 +143,69 @@ public class ReviewCompareAnnotationSupport {
}
}
+ /**
+ * Jumps to the next annotation according to the given direction.
+ *
+ * @param direction
+ * the search direction
+ * @return the selected annotation or <code>null</code> if none
+ */
+ public Annotation gotoAnnotation(Direction direction) {
+ Position leftPosition = new Position(0, 0);
+ Annotation leftAnnotation = findAnnotation(leftSourceViewer, direction, leftPosition, leftAnnotationModel);
+ Position rightPosition = new Position(0, 0);
+ Annotation rightAnnotation = findAnnotation(rightSourceViewer, direction, rightPosition, rightAnnotationModel);
+ if (leftAnnotation == null && rightAnnotation != null) {
+ selectAndReveal(rightSourceViewer, rightPosition);
+ return rightAnnotation;
+ } else if (leftAnnotation != null && rightAnnotation == null) {
+ selectAndReveal(leftSourceViewer, leftPosition);
+ return leftAnnotation;
+ } else if (leftAnnotation != null && rightAnnotation != null) {
+ if ((direction.isForwards() && leftPosition.offset <= rightPosition.offset)
+ || (direction.isBackwards() && leftPosition.offset >= rightPosition.offset)) {
+ selectAndReveal(leftSourceViewer, leftPosition);
+ return leftAnnotation;
+ } else {
+ selectAndReveal(rightSourceViewer, rightPosition);
+ return rightAnnotation;
+ }
+ }
+ return null;
+ }
+
+ // adapted from {@link AbstractTextEditor#selectAndReveal(int, int)}
+ private void selectAndReveal(MergeSourceViewer sourceViewer, Position position) {
+ StyledText widget = sourceViewer.getSourceViewer().getTextWidget();
+ widget.setRedraw(false);
+ {
+ adjustHighlightRange(sourceViewer.getSourceViewer(), position.offset, position.length);
+ sourceViewer.getSourceViewer().revealRange(position.offset, position.length);
+ sourceViewer.getSourceViewer().setSelectedRange(position.offset, position.length);
+ }
+ widget.setRedraw(true);
+ }
+
+ // adapted from {@link AbstractTextEditor#selectAndReveal(int, int)}
+ protected void adjustHighlightRange(SourceViewer sourceViewer, int offset, int length) {
+ if (sourceViewer instanceof ITextViewerExtension5) {
+ ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer;
+ extension.exposeModelRange(new Region(offset, length));
+ } else if (!isVisible(sourceViewer, offset, length)) {
+ sourceViewer.resetVisibleRegion();
+ }
+ }
+
+ // adapted from {@link AbstractTextEditor#selectAndReveal(int, int)}
+ private boolean isVisible(SourceViewer viewer, int offset, int length) {
+ if (viewer instanceof ITextViewerExtension5) {
+ ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
+ IRegion overlap = extension.modelRange2WidgetRange(new Region(offset, length));
+ return overlap != null;
+ }
+ return viewer.overlapsWithVisibleRegion(offset, length);
+ }
+
public void setReviewItem(IFileItem item, ReviewBehavior behavior) {
leftAnnotationModel.setItem(item.getBase(), behavior);
rightAnnotationModel.setItem(item.getTarget(), behavior);
@@ -181,6 +214,7 @@ public class ReviewCompareAnnotationSupport {
try {
// if listeners exist, just make sure the hover hack is in there
leftViewerListener.forceCustomAnnotationHover();
+ rightViewerListener.forceCustomAnnotationHover();
} catch (Exception e) {
StatusHandler.log(new Status(IStatus.ERROR, ReviewsUiPlugin.PLUGIN_ID,
"Error attaching annotation hover", e));
@@ -189,14 +223,6 @@ public class ReviewCompareAnnotationSupport {
});
}
- private boolean isListenerFor(ReviewCompareInputListener listener, MergeSourceViewer viewer,
- ReviewAnnotationModel annotationModel) {
- if (listener == null) {
- return false;
- }
- return listener.isListenerFor(viewer, annotationModel);
- }
-
private ReviewCompareInputListener registerInputListener(final MergeSourceViewer sourceViewer,
final ReviewAnnotationModel annotationModel) {
ReviewCompareInputListener listener = new ReviewCompareInputListener(sourceViewer, annotationModel);
@@ -208,4 +234,101 @@ public class ReviewCompareAnnotationSupport {
return listener;
}
+ /**
+ * Returns the annotation closest to the given range respecting the given direction. If an annotation is found, the
+ * annotations current position is copied into the provided annotation position.
+ *
+ * @param viewer
+ * the viewer
+ * @param direction
+ * the search direction
+ * @param annotationPosition
+ * the position of the found annotation
+ * @param annotationModel
+ * the annotation model to process
+ * @return the found annotation
+ * @see borrowed and adapted from {@link AbstractTextEditor}
+ */
+ protected Annotation findAnnotation(MergeSourceViewer viewer, Direction direction, Position annotationPosition,
+ ReviewAnnotationModel annotationModel) {
+
+ ITextSelection selection = (ITextSelection) viewer.getSourceViewer().getSelectionProvider().getSelection();
+ final int offset = selection.getOffset();
+ final int length = selection.getLength();
+
+ Annotation nextAnnotation = null;
+ Position nextAnnotationPosition = null;
+ Annotation containingAnnotation = null;
+ Position containingAnnotationPosition = null;
+ boolean currentAnnotation = false;
+
+ IDocument document = annotationModel.getDocument();
+ if (document == null) {
+ return null;
+ }
+
+ int endOfDocument = document.getLength();
+ int distance = Integer.MAX_VALUE;
+
+ Iterator<CommentAnnotation> e = annotationModel.getAnnotationIterator();
+ while (e.hasNext()) {
+ CommentAnnotation a = e.next();
+
+ Position p = a.getPosition();
+ if (p == null) {
+ continue;
+ }
+
+ if (direction.isForwards() && p.offset == offset || direction.isBackwards()
+ && p.offset + p.getLength() == offset + length) {// || p.includes(offset)) {
+ if (containingAnnotation == null
+ || (direction.isForwards() && p.length >= containingAnnotationPosition.length || direction.isBackwards()
+ && p.length >= containingAnnotationPosition.length)) {
+ containingAnnotation = a;
+ containingAnnotationPosition = p;
+ currentAnnotation = p.length == length;
+ }
+ } else {
+ int currentDistance = 0;
+
+ if (direction.isForwards()) {
+ currentDistance = p.getOffset() - offset;
+ if (currentDistance < 0) {
+ currentDistance = endOfDocument + currentDistance;
+ }
+
+ if (currentDistance < distance || currentDistance == distance
+ && p.length < nextAnnotationPosition.length) {
+ distance = currentDistance;
+ nextAnnotation = a;
+ nextAnnotationPosition = p;
+ }
+ } else {
+ currentDistance = offset + length - (p.getOffset() + p.length);
+ if (currentDistance < 0) {
+ currentDistance = endOfDocument + currentDistance;
+ }
+
+ if (currentDistance < distance || currentDistance == distance
+ && p.length < nextAnnotationPosition.length) {
+ distance = currentDistance;
+ nextAnnotation = a;
+ nextAnnotationPosition = p;
+ }
+ }
+ }
+ }
+ if (containingAnnotationPosition != null && (!currentAnnotation || nextAnnotation == null)) {
+ annotationPosition.setOffset(containingAnnotationPosition.getOffset());
+ annotationPosition.setLength(containingAnnotationPosition.getLength());
+ return containingAnnotation;
+ }
+ if (nextAnnotationPosition != null) {
+ annotationPosition.setOffset(nextAnnotationPosition.getOffset());
+ annotationPosition.setLength(nextAnnotationPosition.getLength());
+ }
+
+ return nextAnnotation;
+ }
+
}
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewItemCompareEditorInput.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewItemCompareEditorInput.java
index 6ba1253..6fdbda0 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewItemCompareEditorInput.java
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/compare/ReviewItemCompareEditorInput.java
@@ -9,32 +9,54 @@
* Atlassian - initial API and implementation
* Tasktop Technologies - improvements
* Sebastien Dubois (Ericsson) - Improvements for bug 400266
+ * Guy Perron (Ericsson) - Bug 422673 Insert annotation navigation
******************************************************************************/
package org.eclipse.mylyn.internal.reviews.ui.compare;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.compare.CompareViewerPane;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.compare.structuremergeviewer.StructureDiffViewer;
+import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylyn.internal.reviews.ui.Messages;
+import org.eclipse.mylyn.internal.reviews.ui.ReviewsImages;
+import org.eclipse.mylyn.internal.reviews.ui.ReviewsUiPlugin;
import org.eclipse.mylyn.reviews.ui.ReviewBehavior;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.services.IServiceLocator;
/**
* @author Steffen Pingel
* @author Sebastien Dubois
* @author Miles Parker
+ * @author Guy Perron
*/
public abstract class ReviewItemCompareEditorInput extends CompareEditorInput {
final ReviewBehavior behavior;
+ private IHandlerActivation gotoNextCommentHandler;
+
+ private IHandlerActivation gotoPreviousCommentHandler;
+
public ReviewItemCompareEditorInput(CompareConfiguration configuration, ReviewBehavior behavior) {
super(configuration);
this.behavior = behavior;
@@ -81,7 +103,64 @@ public abstract class ReviewItemCompareEditorInput extends CompareEditorInput {
if (input instanceof FileItemNode && ((FileItemNode) input).getFileItem() != null) {
ReviewCompareAnnotationSupport support = ReviewCompareAnnotationSupport.getAnnotationSupport(contentViewer);
support.setReviewItem(((FileItemNode) input).getFileItem(), behavior);
+
+ if (gotoNextCommentHandler == null && gotoPreviousCommentHandler == null) {
+ initializeGotoCommentHandlers(parent, support);
+ }
}
return contentViewer;
}
+
+ private void initializeGotoCommentHandlers(Composite parent, ReviewCompareAnnotationSupport support) {
+ ToolBarManager tbm = CompareViewerPane.getToolBarManager(parent);
+ if (tbm != null) {
+ IServiceLocator serviceLocator = getServiceLocator();
+ if (serviceLocator != null) {
+ final IHandlerService handlerService = (IHandlerService) serviceLocator.getService(IHandlerService.class);
+ if (handlerService != null) {
+ gotoNextCommentHandler = handlerService.activateHandler(ReviewsUiPlugin.PLUGIN_ID
+ + ".commands.navigate.comment.next", //$NON-NLS-1$
+ new GotoCommentHandler(Direction.FORWARDS, support));
+ gotoPreviousCommentHandler = handlerService.activateHandler(ReviewsUiPlugin.PLUGIN_ID
+ + ".commands.navigate.comment.previous", //$NON-NLS-1$
+ new GotoCommentHandler(Direction.BACKWARDS, support));
+ final List<IHandlerActivation> activations = new ArrayList<IHandlerActivation>(Arrays.asList(
+ gotoNextCommentHandler, gotoPreviousCommentHandler));
+ parent.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ handlerService.deactivateHandlers(activations);
+ activations.clear();
+ }
+ });
+ }
+
+ CommandContributionItemParameter p = new CommandContributionItemParameter(serviceLocator, //
+ ReviewsUiPlugin.PLUGIN_ID + ".navigate.comment.next", //$NON-NLS-1$
+ ReviewsUiPlugin.PLUGIN_ID + ".commands.navigate.comment.next", //$NON-NLS-1$ // command id
+ CommandContributionItem.STYLE_PUSH);
+ p.icon = ReviewsImages.NEXT_COMMENT;
+ p.label = Messages.Reviews_NextComment;
+ if (p.label.length() > 0) {
+ p.mnemonic = p.label.substring(0, 1);
+ }
+ p.tooltip = Messages.Reviews_NextComment_Tooltip;
+
+ tbm.appendToGroup("navigation", new CommandContributionItem(p)); //$NON-NLS-1$
+
+ p = new CommandContributionItemParameter(serviceLocator, //
+ ReviewsUiPlugin.PLUGIN_ID + ".navigate.comment.previous", //$NON-NLS-1$
+ ReviewsUiPlugin.PLUGIN_ID + ".commands.navigate.comment.previous", //$NON-NLS-1$ // command id
+ CommandContributionItem.STYLE_PUSH);
+ p.icon = ReviewsImages.PREVIOUS_COMMENT;
+ p.label = Messages.Reviews_PreviousComment;
+ if (p.label.length() > 0) {
+ p.mnemonic = p.label.substring(0, 1);
+ }
+ p.tooltip = Messages.Reviews_PreviousComment_Tooltip;
+ tbm.appendToGroup("navigation", new CommandContributionItem(p)); //$NON-NLS-1$
+ tbm.update(true);
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/messages.properties b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/messages.properties
index f747276..e56c497 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/messages.properties
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/messages.properties
@@ -3,4 +3,11 @@ Reviews_AddCommentDialog_Message={0} line {1}
Reviews_GeneralCommentsText=Global
Reviews_RetrievingContents=[Retrieving contents...]
Reviews_RetrievingDetails=[Retrieving details...]
-Reviews_UpdateFailure=Retrieval problem \ No newline at end of file
+Reviews_UpdateFailure=Retrieval problem
+
+
+Reviews_NextComment = Next Comment
+Reviews_NextComment_Tooltip = Navigates to the next review comment.
+
+Reviews_PreviousComment = Previous Comment
+Reviews_PreviousComment_Tooltip = Navigates to the previous review comment.