package de.ovgu.cide.editor.inlineprojection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationPainter;
import org.eclipse.jface.text.source.IAnnotationAccess;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISharedTextColors;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.projection.IProjectionListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
import de.ovgu.cide.features.IFeature;
import de.ovgu.cide.utils.ColorHelper;
public class InlineProjectionSupport {
/**
* Key of the projection annotation model inside the visual annotation
* model. Also internally used as key for the projection drawing strategy.
*/
public final static Object INLINEPROJECTION = new Object();
private static class InlineProjectionAnnotationsPainter extends
AnnotationPainter {
/**
* Creates a new painter indicating the location of collapsed regions.
*
* @param sourceViewer
* the source viewer for the painter
* @param access
* the annotation access
*/
public InlineProjectionAnnotationsPainter(ISourceViewer sourceViewer,
IAnnotationAccess access) {
super(sourceViewer, access);
}
/*
* @see org.eclipse.jface.text.source.AnnotationPainter#findAnnotationModel(org.eclipse.jface.text.source.ISourceViewer)
*/
protected IAnnotationModel findAnnotationModel(
ISourceViewer sourceViewer) {
if (sourceViewer instanceof InlineProjectionSourceViewer) {
InlineProjectionSourceViewer projectionViewer = (InlineProjectionSourceViewer) sourceViewer;
return projectionViewer.getInlineProjectionAnnotationModel();
}
return null;
}
/*
* @see org.eclipse.jface.text.source.AnnotationPainter#skip(org.eclipse.jface.text.source.Annotation)
*/
protected boolean skip(Annotation annotation) {
if (annotation instanceof InlineProjectionAnnotation)
return !((InlineProjectionAnnotation) annotation).isCollapsed();
return super.skip(annotation);
}
}
private static class InlineProjectionDrawingStrategy implements
AnnotationPainter.IDrawingStrategy {
/*
* @see org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy#draw(org.eclipse.swt.graphics.GC,
* org.eclipse.swt.custom.StyledText, int, int,
* org.eclipse.swt.graphics.Color)
*/
public void draw(Annotation annotation, GC gc, StyledText textWidget,
int offset, int length, Color color) {
if (annotation instanceof InlineProjectionAnnotation) {
InlineProjectionAnnotation projectionAnnotation = (InlineProjectionAnnotation) annotation;
if (projectionAnnotation.isCollapsed()) {
if (gc != null) {
// StyledTextContent content= textWidget.getContent();
// int line= content.getLineAtOffset(offset);
// int lineStart= content.getOffsetAtLine(line);
// String text= content.getLine(line);
// int lineLength= text == null ? 0 : text.length();
// int lineEnd= lineStart + lineLength;
Point p = textWidget.getLocationAtOffset(offset + 1);
Color c = gc.getForeground();
if (annotation instanceof ColoredInlineProjectionAnnotation) {
Set<IFeature> colors = ((ColoredInlineProjectionAnnotation) annotation)
.getColors();
Color combinedColor = ColorHelper
.getCombinedColor(colors);
gc.setForeground(combinedColor);
} else
gc.setForeground(color);
FontMetrics metrics = gc.getFontMetrics();
int top = p.y;
int bottom = p.y + metrics.getHeight();
int x = p.x;
gc.drawLine(x - 2, top, x - 2, bottom);
gc.drawLine(x - 1, top, x - 1, bottom);
gc.drawLine(x, top, x, bottom);
gc.drawLine(x - 4, top, x + 2, top);
gc.drawLine(x - 4, bottom, x + 2, bottom);
// gc.drawLine(p.x+1, p.y + leading, p.x+1, p.y +
// leading+ascent);
// int third= width/3;
// int dotsVertical= p.y + baseline - 1;
// gc.drawPoint(p.x + third, dotsVertical);
// gc.drawPoint(p.x + width - third, dotsVertical);
// Color bc= gc.getBackground();
// gc.setBackground(color);
//
// gc.fillRectangle(textWidget.getClientArea());
gc.setForeground(c);
// gc.setBackground(bc);
} else {
textWidget.redrawRange(offset, length, true);
}
}
}
}
}
private class ProjectionListener implements IProjectionListener,
IInlineProjectionListener {
/*
* @see org.eclipse.jface.text.source.projection.IProjectionListener#projectionEnabled()
*/
public void projectionEnabled() {
}
/*
* @see org.eclipse.jface.text.source.projection.IProjectionListener#projectionDisabled()
*/
public void projectionDisabled() {
}
public void inlineProjectionDisabled() {
doInlineDisableProjection();
}
public void inlineProjectionEnabled() {
doInlineEnableProjection();
}
}
private InlineProjectionSourceViewer fViewer;
private IAnnotationAccess fAnnotationAccess;
private ISharedTextColors fSharedTextColors;
private List fSummarizableTypes;
private IInformationControlCreator fInformationControlCreator;
private ProjectionListener fProjectionListener;
private InlineProjectionAnnotationsPainter fPainter;
private InlineProjectionRulerColumn fColumn;
/**
* @since 3.1
*/
private AnnotationPainter.IDrawingStrategy fDrawingStrategy;
/**
* Creates new projection support for the given projection viewer.
* Initially, no annotation types are summarized. A default hover control
* creator and a default drawing strategy are used.
*
* @param viewer
* the projection viewer
* @param annotationAccess
* the annotation access
* @param sharedTextColors
* the shared text colors to use
*/
public InlineProjectionSupport(InlineProjectionSourceViewer viewer,
IAnnotationAccess annotationAccess,
ISharedTextColors sharedTextColors) {
fViewer = viewer;
fAnnotationAccess = annotationAccess;
fSharedTextColors = sharedTextColors;
}
/**
* Marks the given annotation type to be considered when creating summaries
* for collapsed regions of the projection viewer.
* <p>
* A summary is an annotation that gets created out of all annotations with
* a type that has been registered through this method and that are inside
* the folded region.
* </p>
*
* @param annotationType
* the annotation type to consider
*/
public void addSummarizableAnnotationType(String annotationType) {
if (fSummarizableTypes == null) {
fSummarizableTypes = new ArrayList();
fSummarizableTypes.add(annotationType);
} else if (!fSummarizableTypes.contains(annotationType))
fSummarizableTypes.add(annotationType);
}
/**
* Marks the given annotation type to be ignored when creating summaries for
* collapsed regions of the projection viewer. This method has only an
* effect when <code>addSummarizableAnnotationType</code> has been called
* before for the give annotation type.
* <p>
* A summary is an annotation that gets created out of all annotations with
* a type that has been registered through this method and that are inside
* the folded region.
* </p>
*
* @param annotationType
* the annotation type to remove
*/
public void removeSummarizableAnnotationType(String annotationType) {
if (fSummarizableTypes != null)
fSummarizableTypes.remove(annotationType);
if (fSummarizableTypes.size() == 0)
fSummarizableTypes = null;
}
/**
* Sets the hover control creator that is used for the annotation hovers
* that are shown in the projection viewer's projection ruler column.
*
* @param creator
* the hover control creator
*/
public void setHoverControlCreator(IInformationControlCreator creator) {
fInformationControlCreator = creator;
}
/**
* Sets the drawing strategy that the projection support's annotation
* painter uses to draw the indication of collapsed regions onto the
* projection viewer's text widget. When <code>null</code> is passed in,
* the drawing strategy is reset to the default. In order to avoid any
* representation use
* {@link org.eclipse.jface.text.source.AnnotationPainter.NullStrategy}.
*
* @param strategy
* the drawing strategy or <code>null</code> to reset the
* strategy to the default
* @since 3.1
*/
public void setAnnotationPainterDrawingStrategy(
AnnotationPainter.IDrawingStrategy strategy) {
fDrawingStrategy = strategy;
}
/**
* Returns the drawing strategy to be used by the support's annotation
* painter.
*
* @return the drawing strategy to be used by the support's annotation
* painter
* @since 3.1
*/
private AnnotationPainter.IDrawingStrategy getDrawingStrategy() {
if (fDrawingStrategy == null)
fDrawingStrategy = new InlineProjectionDrawingStrategy();
return fDrawingStrategy;
}
/**
* Installs this projection support on its viewer.
*/
public void install() {
// TODO fViewer.setProjectionSummary(createProjectionSummary());
fProjectionListener = new ProjectionListener();
fViewer.addProjectionListener(fProjectionListener);
}
/**
* Disposes this projection support.
*/
public void dispose() {
if (fProjectionListener != null) {
fViewer.removeProjectionListener(fProjectionListener);
fProjectionListener = null;
}
}
/**
* Enables projection mode. If not yet done, installs the projection ruler
* column in the viewer's vertical ruler and installs a painter that
* indicate the locations of collapsed regions.
*
*/
protected void doInlineEnableProjection() {
if (fPainter == null) {
fPainter = new InlineProjectionAnnotationsPainter(fViewer,
fAnnotationAccess);
fPainter.addDrawingStrategy(INLINEPROJECTION, getDrawingStrategy());
fPainter.addAnnotationType(InlineProjectionAnnotation.TYPE,
INLINEPROJECTION);
fPainter.setAnnotationTypeColor(InlineProjectionAnnotation.TYPE,
fSharedTextColors.getColor(getColor()));
fViewer.addPainter(fPainter);
}
if (fColumn == null) {
fColumn = new InlineProjectionRulerColumn(9, fAnnotationAccess);
fColumn.addAnnotationType(InlineProjectionAnnotation.TYPE);
fColumn.setHover(createProjectionAnnotationHover());
fViewer.addVerticalRulerColumn(fColumn);
}
fColumn.setModel(fViewer.getVisualAnnotationModel());
}
/**
* Removes the projection ruler column and the painter from the projection
* viewer.
*/
protected void doInlineDisableProjection() {
if (fPainter != null) {
fViewer.removePainter(fPainter);
fPainter.dispose();
fPainter = null;
}
if (fColumn != null) {
fViewer.removeVerticalRulerColumn(fColumn);
fColumn = null;
}
}
//
// private InlineProjectionSummary createProjectionSummary() {
// InlineProjectionSummary summary = new InlineProjectionSummary(fViewer,
// fAnnotationAccess);
// if (fSummarizableTypes != null) {
// int size = fSummarizableTypes.size();
// for (int i = 0; i < size; i++)
// summary.addAnnotationType((String) fSummarizableTypes.get(i));
// }
// return summary;
// }
private IAnnotationHover createProjectionAnnotationHover() {
InlineProjectionAnnotationHover hover = new InlineProjectionAnnotationHover();
hover.setHoverControlCreator(fInformationControlCreator);
return hover;
}
/**
* Implements the contract of
* {@link org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)}
* by forwarding the adapter requests to the given viewer.
*
* @param viewer
* the viewer
* @param required
* the required class of the adapter
* @return the adapter or <code>null</code>
*
*/
public Object getAdapter(ISourceViewer viewer, Class required) {
if (InlineProjectionAnnotationModel.class.equals(required)) {
if (viewer instanceof InlineProjectionSourceViewer) {
InlineProjectionSourceViewer projectionViewer = (InlineProjectionSourceViewer) viewer;
return projectionViewer.getInlineProjectionAnnotationModel();
}
}
return null;
}
private RGB getColor() {
// TODO read out preference settings
Color c = Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
return c.getRGB();
}
}