package de.ovgu.cide.language.jdt.editor.inlineprojection; import java.util.Iterator; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationAccess; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IAnnotationModelExtension; import org.eclipse.jface.text.source.projection.IProjectionPosition; import org.eclipse.jface.text.source.projection.ProjectionAnnotation; import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; import org.eclipse.jface.text.source.projection.ProjectionSupport; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; /** * A ruler column for controlling the behavior of a * {@link org.eclipse.jface.text.source.projection.ProjectionViewer}. * * @since 3.0 */ class InlineProjectionRulerColumn extends AnnotationRulerColumn { private ProjectionAnnotation fCurrentAnnotation; /** * Creates a new projection ruler column. * * @param model * the column's annotation model * @param width * the width in pixels * @param annotationAccess * the annotation access */ public InlineProjectionRulerColumn(IAnnotationModel model, int width, IAnnotationAccess annotationAccess) { super(model, width, annotationAccess); } /** * Creates a new projection ruler column. * * @param width * the width in pixels * @param annotationAccess * the annotation access */ public InlineProjectionRulerColumn(int width, IAnnotationAccess annotationAccess) { super(width, annotationAccess); } /* * @see * org.eclipse.jface.text.source.AnnotationRulerColumn#mouseClicked(int) */ protected void mouseClicked(int line) { clearCurrentAnnotation(); ProjectionAnnotation annotation = findAnnotation(line, true); if (annotation != null) { ProjectionAnnotationModel model = (ProjectionAnnotationModel) getModel(); model.toggleExpansionState(annotation); } } /** * Returns the projection annotation of the column's annotation model that * contains the given line. * * @param line * the line * @param exact * <code>true</code> if the annotation range must match exactly * @return the projection annotation containing the given line */ private ProjectionAnnotation findAnnotation(int line, boolean exact) { ProjectionAnnotation previousAnnotation = null; IAnnotationModel model = getModel(); if (model != null) { IDocument document = getCachedTextViewer().getDocument(); int previousDistance = Integer.MAX_VALUE; Iterator<?> e = model.getAnnotationIterator(); while (e.hasNext()) { Object next = e.next(); if (next instanceof ProjectionAnnotation) { ProjectionAnnotation annotation = (ProjectionAnnotation) next; Position p = model.getPosition(annotation); if (p == null) continue; int distance = getDistance(annotation, p, document, line); if (distance == -1) continue; if (!exact) { if (distance < previousDistance) { previousAnnotation = annotation; previousDistance = distance; } } else if (distance == 0) { previousAnnotation = annotation; } } } } return previousAnnotation; } /** * Returns the distance of the given line to the start line of the given * position in the given document. The distance is <code>-1</code> when the * line is not included in the given position. * * @param annotation * the annotation * @param position * the position * @param document * the document * @param line * the line * @return <code>-1</code> if line is not contained, a position number * otherwise */ private int getDistance(ProjectionAnnotation annotation, Position position, IDocument document, int line) { if (position.getOffset() > -1 && position.getLength() > -1) { try { int startLine = document.getLineOfOffset(position.getOffset()); int endLine = document.getLineOfOffset(position.getOffset() + position.getLength()); if (startLine <= line && line < endLine) { if (annotation.isCollapsed()) { int captionOffset; if (position instanceof IProjectionPosition) captionOffset = ((IProjectionPosition) position) .computeCaptionOffset(document); else captionOffset = 0; int captionLine = document.getLineOfOffset(position .getOffset() + captionOffset); if (startLine <= captionLine && captionLine < endLine) return Math.abs(line - captionLine); } return line - startLine; } } catch (BadLocationException x) { } } return -1; } private boolean clearCurrentAnnotation() { if (fCurrentAnnotation != null) { fCurrentAnnotation.setRangeIndication(false); fCurrentAnnotation = null; return true; } return false; } /* * @see * org.eclipse.jface.text.source.IVerticalRulerColumn#createControl(org. * eclipse.jface.text.source.CompositeRuler, * org.eclipse.swt.widgets.Composite) */ public Control createControl(CompositeRuler parentRuler, Composite parentControl) { Control control = super.createControl(parentRuler, parentControl); // set background Display display = parentControl.getDisplay(); Color background = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); control.setBackground(background); // install hover listener control.addMouseTrackListener(new MouseTrackAdapter() { public void mouseExit(MouseEvent e) { if (clearCurrentAnnotation()) redraw(); } }); // install mouse move listener control.addMouseMoveListener(new MouseMoveListener() { public void mouseMove(MouseEvent e) { boolean redraw = false; ProjectionAnnotation annotation = findAnnotation( toDocumentLineNumber(e.y), false); if (annotation != fCurrentAnnotation) { if (fCurrentAnnotation != null) { fCurrentAnnotation.setRangeIndication(false); redraw = true; } fCurrentAnnotation = annotation; if (fCurrentAnnotation != null && !fCurrentAnnotation.isCollapsed()) { fCurrentAnnotation.setRangeIndication(true); redraw = true; } } if (redraw) redraw(); } }); return control; } /* * @see * org.eclipse.jface.text.source.AnnotationRulerColumn#setModel(org.eclipse * .jface.text.source.IAnnotationModel) */ public void setModel(IAnnotationModel model) { if (model instanceof IAnnotationModelExtension) { IAnnotationModelExtension extension = (IAnnotationModelExtension) model; model = extension.getAnnotationModel(ProjectionSupport.PROJECTION); } super.setModel(model); } /* * @seeorg.eclipse.jface.text.source.AnnotationRulerColumn# * isPropagatingMouseListener() */ protected boolean isPropagatingMouseListener() { return false; } /* * @see * org.eclipse.jface.text.source.AnnotationRulerColumn#hasAnnotation(int) */ protected boolean hasAnnotation(int lineNumber) { return findAnnotation(lineNumber, true) != null; } }