package org.erlide.ui.editors.erl;
import java.util.Iterator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.AnnotationPreference;
import org.eclipse.ui.texteditor.AnnotationPreferenceLookup;
import org.erlide.ui.editors.erl.hover.ErlangAnnotationIterator;
import org.erlide.ui.editors.erl.hover.IErlangAnnotation;
public class AnnotationSupport {
private final ErlangEditor editor;
private final AnnotationPreferenceLookup annotationPreferenceLookup;
public AnnotationSupport(final ErlangEditor editor,
final AnnotationPreferenceLookup annotationPreferenceLookup) {
this.editor = editor;
this.annotationPreferenceLookup = annotationPreferenceLookup;
}
/**
* Returns whether the given annotation is configured as a target for the
* "Go to Next/Previous Annotation" actions
*
* @param annotation
* the annotation
* @return <code>true</code> if this is a target, <code>false</code>
* otherwise
* @since 3.0
*/
public boolean isNavigationTarget(final Annotation annotation) {
final IPreferenceStore preferences = EditorsUI.getPreferenceStore();
final AnnotationPreference preference = annotationPreferenceLookup
.getAnnotationPreference(annotation);
final String key = preference == null ? null
: preference.getIsGoToNextNavigationTargetKey();
return key != null && preferences.getBoolean(key);
}
public Annotation gotoAnnotation(final boolean forward) {
final ITextSelection selection = (ITextSelection) editor.getSelectionProvider()
.getSelection();
final Position position = new Position(0, 0);
final Annotation annotation = getNextAnnotation(selection.getOffset(),
selection.getLength(), forward, position);
editor.setStatusLineErrorMessage(null);
editor.setStatusLineMessage(null);
if (annotation != null) {
updateAnnotationViews(annotation);
editor.selectAndReveal(position.getOffset(), position.getLength());
editor.setStatusLineMessage(annotation.getText());
}
return annotation;
}
/**
* Returns the annotation closest to the given range respecting the given
* direction. If an annotation is found, the annotation's current position
* is copied into the provided position.
*/
private Annotation getNextAnnotation(final int offset, final int length,
final boolean forward, final Position annotationPosition) {
Annotation nextAnnotation = null;
Position nextAnnotationPosition = null;
Annotation containingAnnotation = null;
Position containingAnnotationPosition = null;
boolean currentAnnotation = false;
final IDocument document = editor.getDocumentProvider()
.getDocument(editor.getEditorInput());
final int endOfDocument = document.getLength();
int distance = Integer.MAX_VALUE;
final IAnnotationModel model = editor.getDocumentProvider()
.getAnnotationModel(editor.getEditorInput());
final Iterator<Annotation> e = new ErlangAnnotationIterator(model, true, true);
while (e.hasNext()) {
final Annotation a = e.next();
if (a instanceof IErlangAnnotation && ((IErlangAnnotation) a).hasOverlay()
|| !isNavigationTarget(a)) {
continue;
}
final Position p = model.getPosition(a);
if (p == null) {
continue;
}
if (forward && p.offset == offset
|| !forward && p.offset + p.getLength() == offset + length) {
// || p.includes(offset))
if (containingAnnotation == null || containingAnnotationPosition != null
&& (forward && p.length >= containingAnnotationPosition.length
|| !forward
&& p.length < containingAnnotationPosition.length)) {
containingAnnotation = a;
containingAnnotationPosition = p;
currentAnnotation = p.length == length;
}
} else {
int currentDistance = 0;
if (forward) {
currentDistance = p.getOffset() - offset;
if (currentDistance < 0) {
currentDistance = endOfDocument + currentDistance;
}
if (currentDistance < distance || currentDistance == distance
&& nextAnnotationPosition != null
&& 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
&& nextAnnotationPosition != null
&& 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;
}
private void updateAnnotationViews(final Annotation annotation) {
}
}