package de.ovgu.cide.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); } /* * @see org.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; } }