+++ /dev/null
-/**********************************************************************
-Copyright (c) 2000, 2002 IBM Corp. and others.
-All rights reserved. This program and the accompanying materials
-are made available under the terms of the Common Public License v1.0
-which accompanies this distribution, and is available at
-http://www.eclipse.org/legal/cpl-v10.html
-
-Contributors:
- IBM Corporation - Initial implementation
-**********************************************************************/
-
-package net.sourceforge.phpeclipse.phpeditor;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import net.sourceforge.phpdt.ui.text.JavaTextTools;
-import net.sourceforge.phpeclipse.PHPeclipsePlugin;
-
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.ITextListener;
-import org.eclipse.jface.text.ITextViewer;
-import org.eclipse.jface.text.ITextViewerExtension3;
-import org.eclipse.jface.text.Position;
-import org.eclipse.jface.text.Region;
-import org.eclipse.jface.text.TextEvent;
-import org.eclipse.jface.text.source.Annotation;
-import org.eclipse.jface.text.source.IAnnotationModel;
-import org.eclipse.jface.text.source.IAnnotationModelListener;
-import org.eclipse.jface.text.source.IVerticalRulerInfo;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseMoveListener;
-import org.eclipse.swt.events.PaintEvent;
-import org.eclipse.swt.events.PaintListener;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Cursor;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.RGB;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Canvas;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-
-/**
- *
- */
-public class OverviewRuler implements IVerticalRulerInfo {
-
- /**
- * Internal listener class.
- */
- class InternalListener implements ITextListener, IAnnotationModelListener {
-
- /*
- * @see ITextListener#textChanged
- */
- public void textChanged(TextEvent e) {
- if (fTextViewer != null && e.getDocumentEvent() == null && e.getViewerRedrawState()) {
- // handle only changes of visible document
- redraw();
- }
- }
-
- /*
- * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
- */
- public void modelChanged(IAnnotationModel model) {
- update();
- }
- }
-
- /**
- * Filters problems based on their types.
- */
- class FilterIterator implements Iterator {
-
- private final static int IGNORE = 0;
- private final static int TEMPORARY = 1;
- private final static int PERSISTENT = 2;
-
- private Iterator fIterator;
- private AnnotationType fType;
- private IProblemAnnotation fNext;
- private int fTemporary;
-
- public FilterIterator(AnnotationType type) {
- this(type, IGNORE);
- }
-
- public FilterIterator(AnnotationType type, boolean temporary) {
- this(type, temporary ? TEMPORARY : PERSISTENT);
- }
-
- private FilterIterator(AnnotationType type, int temporary) {
- fType = type;
- fTemporary = temporary;
- if (fModel != null) {
- fIterator = fModel.getAnnotationIterator();
- skip();
- }
- }
-
- private void skip() {
- while (fIterator.hasNext()) {
- Object next = fIterator.next();
- if (next instanceof IProblemAnnotation) {
- fNext = (IProblemAnnotation) next;
- AnnotationType type = fNext.getAnnotationType();
- if (fType == AnnotationType.ALL || fType == type) {
- if (fTemporary == IGNORE)
- return;
- if (fTemporary == TEMPORARY && fNext.isTemporary())
- return;
- if (fTemporary == PERSISTENT && !fNext.isTemporary())
- return;
- }
- }
- }
- fNext = null;
- }
-
- /*
- * @see Iterator#hasNext()
- */
- public boolean hasNext() {
- return fNext != null;
- }
- /*
- * @see Iterator#next()
- */
- public Object next() {
- try {
- return fNext;
- } finally {
- if (fModel != null)
- skip();
- }
- }
- /*
- * @see Iterator#remove()
- */
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
-
- private static final int INSET = 2;
- private static final int PROBLEM_HEIGHT_MIN = 4;
- private static boolean PROBLEM_HEIGHT_SCALABLE = false;
-
- /** The model of the overview ruler */
- private IAnnotationModel fModel;
- /** The view to which this ruler is connected */
- private ITextViewer fTextViewer;
- /** The ruler's canvas */
- private Canvas fCanvas;
- /** The drawable for double buffering */
- private Image fBuffer;
- /** The internal listener */
- private InternalListener fInternalListener = new InternalListener();
- /** The width of this vertical ruler */
- private int fWidth;
- /** The hit detection cursor */
- private Cursor fHitDetectionCursor;
- /** The last cursor */
- private Cursor fLastCursor;
- /** Cache for the actual scroll position in pixels */
- private int fScrollPos;
- /** The line of the last mouse button activity */
- private int fLastMouseButtonActivityLine = -1;
- /** The actual problem height */
- private int fProblemHeight = -1;
-
- private Set fAnnotationSet = new HashSet();
- private Map fLayers = new HashMap();
- private Map fColorTable = new HashMap();
-
- /**
- * Constructs a vertical ruler with the given width.
- *
- * @param width the width of the vertical ruler
- */
- public OverviewRuler(int width) {
- fWidth = width;
- }
-
- public Control getControl() {
- return fCanvas;
- }
-
- public int getWidth() {
- return fWidth;
- }
-
- public void setModel(IAnnotationModel model) {
- if (model != fModel || model != null) {
-
- if (fModel != null)
- fModel.removeAnnotationModelListener(fInternalListener);
-
- fModel = model;
-
- if (fModel != null)
- fModel.addAnnotationModelListener(fInternalListener);
-
- update();
- }
- }
-
- public Control createControl(Composite parent, ITextViewer textViewer) {
-
- fTextViewer = textViewer;
-
- fHitDetectionCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
- fCanvas = new Canvas(parent, SWT.NO_BACKGROUND);
-
- fCanvas.addPaintListener(new PaintListener() {
- public void paintControl(PaintEvent event) {
- if (fTextViewer != null)
- doubleBufferPaint(event.gc);
- }
- });
-
- fCanvas.addDisposeListener(new DisposeListener() {
- public void widgetDisposed(DisposeEvent event) {
- handleDispose();
- fTextViewer = null;
- }
- });
-
- fCanvas.addMouseListener(new MouseAdapter() {
- public void mouseDown(MouseEvent event) {
- handleMouseDown(event);
- }
- });
-
- fCanvas.addMouseMoveListener(new MouseMoveListener() {
- public void mouseMove(MouseEvent event) {
- handleMouseMove(event);
- }
- });
-
- if (fTextViewer != null)
- fTextViewer.addTextListener(fInternalListener);
-
- return fCanvas;
- }
-
- /**
- * Disposes the ruler's resources.
- */
- private void handleDispose() {
-
- if (fTextViewer != null) {
- fTextViewer.removeTextListener(fInternalListener);
- fTextViewer = null;
- }
-
- if (fModel != null)
- fModel.removeAnnotationModelListener(fInternalListener);
-
- if (fBuffer != null) {
- fBuffer.dispose();
- fBuffer = null;
- }
-
- if (fHitDetectionCursor != null) {
- fHitDetectionCursor.dispose();
- fHitDetectionCursor = null;
- }
-
- fAnnotationSet.clear();
- fLayers.clear();
- fColorTable.clear();
- }
-
- /**
- * Double buffer drawing.
- */
- private void doubleBufferPaint(GC dest) {
-
- Point size = fCanvas.getSize();
-
- if (size.x <= 0 || size.y <= 0)
- return;
-
- if (fBuffer != null) {
- Rectangle r = fBuffer.getBounds();
- if (r.width != size.x || r.height != size.y) {
- fBuffer.dispose();
- fBuffer = null;
- }
- }
- if (fBuffer == null)
- fBuffer = new Image(fCanvas.getDisplay(), size.x, size.y);
-
- GC gc = new GC(fBuffer);
- try {
- gc.setBackground(fCanvas.getBackground());
- gc.fillRectangle(0, 0, size.x, size.y);
-
- if (fTextViewer instanceof ITextViewerExtension3)
- doPaint1(gc);
- else
- doPaint(gc);
-
- } finally {
- gc.dispose();
- }
-
- dest.drawImage(fBuffer, 0, 0);
- }
-
- private void doPaint(GC gc) {
-
- if (fTextViewer == null)
- return;
-
- Rectangle r = new Rectangle(0, 0, 0, 0);
- int yy, hh = PROBLEM_HEIGHT_MIN;
-
- IDocument document = fTextViewer.getDocument();
- IRegion visible = fTextViewer.getVisibleRegion();
-
- StyledText textWidget = fTextViewer.getTextWidget();
- int maxLines = textWidget.getLineCount();
- fScrollPos = textWidget.getTopPixel();
-
- Point size = fCanvas.getSize();
- int writable = maxLines * textWidget.getLineHeight();
- if (size.y > writable)
- size.y = writable;
-
- List indices = new ArrayList(fLayers.keySet());
- Collections.sort(indices);
-
- for (Iterator iterator = indices.iterator(); iterator.hasNext();) {
- Object layer = iterator.next();
- AnnotationType annotationType = (AnnotationType) fLayers.get(layer);
-
- if (skip(annotationType))
- continue;
-
- boolean[] temporary = new boolean[] { false, true };
- for (int t = 0; t < temporary.length; t++) {
-
- Iterator e = new FilterIterator(annotationType, temporary[t]);
- Color fill = getFillColor(annotationType, temporary[t]);
- Color stroke = getStrokeColor(annotationType, temporary[t]);
-
- for (int i = 0; e.hasNext(); i++) {
-
- Annotation a = (Annotation) e.next();
- Position p = fModel.getPosition(a);
-
- if (p == null || !p.overlapsWith(visible.getOffset(), visible.getLength()))
- continue;
-
- int problemOffset = Math.max(p.getOffset(), visible.getOffset());
- int problemEnd = Math.min(p.getOffset() + p.getLength(), visible.getOffset() + visible.getLength());
- int problemLength = problemEnd - problemOffset;
-
- try {
- if (PROBLEM_HEIGHT_SCALABLE) {
- int numbersOfLines = document.getNumberOfLines(problemOffset, problemLength);
- hh = (numbersOfLines * size.y) / maxLines;
- if (hh < PROBLEM_HEIGHT_MIN)
- hh = PROBLEM_HEIGHT_MIN;
- }
- fProblemHeight = hh;
-
- int startLine = textWidget.getLineAtOffset(problemOffset - visible.getOffset());
- yy = Math.min((startLine * size.y) / maxLines, size.y - hh);
-
- if (fill != null) {
- gc.setBackground(fill);
- gc.fillRectangle(INSET, yy, size.x - (2 * INSET), hh);
- }
-
- if (stroke != null) {
- gc.setForeground(stroke);
- r.x = INSET;
- r.y = yy;
- r.width = size.x - (2 * INSET) - 1;
- r.height = hh;
- gc.setLineWidth(1);
- gc.drawRectangle(r);
- }
- } catch (BadLocationException x) {
- }
- }
- }
- }
- }
-
- private void doPaint1(GC gc) {
-
- if (fTextViewer == null)
- return;
-
- Rectangle r = new Rectangle(0, 0, 0, 0);
- int yy, hh = PROBLEM_HEIGHT_MIN;
-
- ITextViewerExtension3 extension = (ITextViewerExtension3) fTextViewer;
- IDocument document = fTextViewer.getDocument();
- StyledText textWidget = fTextViewer.getTextWidget();
- fScrollPos = textWidget.getTopPixel();
-
- int maxLines = textWidget.getLineCount();
- Point size = fCanvas.getSize();
- int writable = maxLines * textWidget.getLineHeight();
- if (size.y > writable)
- size.y = writable;
-
- List indices = new ArrayList(fLayers.keySet());
- Collections.sort(indices);
-
- for (Iterator iterator = indices.iterator(); iterator.hasNext();) {
- Object layer = iterator.next();
- AnnotationType annotationType = (AnnotationType) fLayers.get(layer);
-
- if (skip(annotationType))
- continue;
-
- boolean[] temporary = new boolean[] { false, true };
- for (int t = 0; t < temporary.length; t++) {
-
- Iterator e = new FilterIterator(annotationType, temporary[t]);
- Color fill = getFillColor(annotationType, temporary[t]);
- Color stroke = getStrokeColor(annotationType, temporary[t]);
-
- for (int i = 0; e.hasNext(); i++) {
-
- Annotation a = (Annotation) e.next();
- Position p = fModel.getPosition(a);
-
- if (p == null)
- continue;
-
- IRegion widgetRegion = extension.modelRange2WidgetRange(new Region(p.getOffset(), p.getLength()));
- if (widgetRegion == null)
- continue;
-
- try {
- if (PROBLEM_HEIGHT_SCALABLE) {
- int numbersOfLines = document.getNumberOfLines(p.getOffset(), p.getLength());
- hh = (numbersOfLines * size.y) / maxLines;
- if (hh < PROBLEM_HEIGHT_MIN)
- hh = PROBLEM_HEIGHT_MIN;
- }
- fProblemHeight = hh;
-
- int startLine = textWidget.getLineAtOffset(widgetRegion.getOffset());
- yy = Math.min((startLine * size.y) / maxLines, size.y - hh);
-
- if (fill != null) {
- gc.setBackground(fill);
- gc.fillRectangle(INSET, yy, size.x - (2 * INSET), hh);
- }
-
- if (stroke != null) {
- gc.setForeground(stroke);
- r.x = INSET;
- r.y = yy;
- r.width = size.x - (2 * INSET) - 1;
- r.height = hh;
- gc.setLineWidth(1);
- gc.drawRectangle(r);
- }
- } catch (BadLocationException x) {
- }
- }
- }
- }
- }
-
- /**
- * Thread-safe implementation.
- * Can be called from any thread.
- */
- public void update() {
- if (fCanvas != null && !fCanvas.isDisposed()) {
- Display d = fCanvas.getDisplay();
- if (d != null) {
- d.asyncExec(new Runnable() {
- public void run() {
- redraw();
- }
- });
- }
- }
- }
-
- /**
- * Redraws the overview ruler.
- */
- private void redraw() {
- if (fCanvas != null && !fCanvas.isDisposed()) {
- GC gc = new GC(fCanvas);
- doubleBufferPaint(gc);
- gc.dispose();
- }
- }
-
- private int[] toLineNumbers(int y_coordinate) {
-
- StyledText textWidget = fTextViewer.getTextWidget();
- int maxLines = textWidget.getContent().getLineCount();
-
- int rulerLength = fCanvas.getSize().y;
- int writable = maxLines * textWidget.getLineHeight();
-
- if (rulerLength > writable)
- rulerLength = writable;
-
- if (y_coordinate >= writable)
- return new int[] { -1, -1 };
-
- int[] lines = new int[2];
-
- int pixel = Math.max(y_coordinate - 1, 0);
- lines[0] = (pixel * maxLines) / rulerLength;
-
- pixel = Math.min(rulerLength, y_coordinate + 1);
- lines[1] = (pixel * maxLines) / rulerLength;
-
- if (fTextViewer instanceof ITextViewerExtension3) {
- ITextViewerExtension3 extension = (ITextViewerExtension3) fTextViewer;
- lines[0] = extension.widgetlLine2ModelLine(lines[0]);
- lines[1] = extension.widgetlLine2ModelLine(lines[1]);
- } else {
- try {
- IRegion visible = fTextViewer.getVisibleRegion();
- int lineNumber = fTextViewer.getDocument().getLineOfOffset(visible.getOffset());
- lines[0] += lineNumber;
- lines[1] += lineNumber;
- } catch (BadLocationException x) {
- }
- }
-
- return lines;
- }
-
- boolean hasAnnotationAt(int y_coordinate) {
- return findBestMatchingLineNumber(toLineNumbers(y_coordinate)) != -1;
- }
-
- private Position getProblemPositionAt(int[] lineNumbers) {
- if (lineNumbers[0] == -1)
- return null;
-
- Position found = null;
-
- try {
- IDocument d = fTextViewer.getDocument();
- IRegion line = d.getLineInformation(lineNumbers[0]);
-
- int start = line.getOffset();
-
- line = d.getLineInformation(lineNumbers[lineNumbers.length - 1]);
- int end = line.getOffset() + line.getLength();
-
- Iterator e = new FilterIterator(AnnotationType.ALL);
- while (e.hasNext()) {
- Annotation a = (Annotation) e.next();
- Position p = fModel.getPosition(a);
- if (start <= p.getOffset() && p.getOffset() < end) {
- if (found == null || p.getOffset() < found.getOffset())
- found = p;
- }
- }
-
- } catch (BadLocationException x) {
- }
-
- return found;
- }
-
- /**
- * Returns the line which best corresponds to one of
- * the underlying problem annotations at the given
- * y ruler coordinate.
- *
- * @return the best matching line or <code>-1</code> if no such line can be found
- * @since 2.1
- */
- private int findBestMatchingLineNumber(int[] lineNumbers) {
- if (lineNumbers == null || lineNumbers.length < 1)
- return -1;
-
- try {
- Position pos = getProblemPositionAt(lineNumbers);
- if (pos == null)
- return -1;
- return fTextViewer.getDocument().getLineOfOffset(pos.getOffset());
- } catch (BadLocationException ex) {
- return -1;
- }
- }
-
- private void handleMouseDown(MouseEvent event) {
- if (fTextViewer != null) {
- int[] lines = toLineNumbers(event.y);
- Position p = getProblemPositionAt(lines);
- if (p != null) {
- fTextViewer.revealRange(p.getOffset(), p.getLength());
- fTextViewer.setSelectedRange(p.getOffset(), p.getLength());
- }
- fTextViewer.getTextWidget().setFocus();
- }
- fLastMouseButtonActivityLine = toDocumentLineNumber(event.y);
- }
-
- private void handleMouseMove(MouseEvent event) {
- if (fTextViewer != null) {
- int[] lines = toLineNumbers(event.y);
- Position p = getProblemPositionAt(lines);
- Cursor cursor = (p != null ? fHitDetectionCursor : null);
- if (cursor != fLastCursor) {
- fCanvas.setCursor(cursor);
- fLastCursor = cursor;
- }
- }
- }
-
- private void handleMouseDoubleClick(MouseEvent event) {
- fLastMouseButtonActivityLine = toDocumentLineNumber(event.y);
- }
-
- public void showAnnotation(AnnotationType annotationType, boolean show) {
- if (show)
- fAnnotationSet.add(annotationType);
- else
- fAnnotationSet.remove(annotationType);
- }
-
- public void setLayer(AnnotationType annotationType, int layer) {
- if (layer >= 0)
- fLayers.put(new Integer(layer), annotationType);
- else {
- Iterator e = fLayers.keySet().iterator();
- while (e.hasNext()) {
- Object key = e.next();
- if (annotationType.equals(fLayers.get(key))) {
- fLayers.remove(key);
- return;
- }
- }
- }
- }
-
- public void setColor(AnnotationType annotationType, Color color) {
- if (color != null)
- fColorTable.put(annotationType, color);
- else
- fColorTable.remove(annotationType);
- }
-
- private boolean skip(AnnotationType annotationType) {
- return !fAnnotationSet.contains(annotationType);
- }
-
- private static RGB interpolate(RGB fg, RGB bg, double scale) {
- return new RGB(
- (int) ((1.0 - scale) * fg.red + scale * bg.red),
- (int) ((1.0 - scale) * fg.green + scale * bg.green),
- (int) ((1.0 - scale) * fg.blue + scale * bg.blue));
- }
-
- private static double greyLevel(RGB rgb) {
- if (rgb.red == rgb.green && rgb.green == rgb.blue)
- return rgb.red;
- return (0.299 * rgb.red + 0.587 * rgb.green + 0.114 * rgb.blue + 0.5);
- }
-
- private static boolean isDark(RGB rgb) {
- return greyLevel(rgb) > 128;
- }
-
- private static Color getColor(RGB rgb) {
- JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
- return textTools.getColorManager().getColor(rgb);
- }
-
- private Color getColor(AnnotationType annotationType, double scale) {
- Color base = (Color) fColorTable.get(annotationType);
- if (base == null)
- return null;
-
- RGB baseRGB = base.getRGB();
- RGB background = fCanvas.getBackground().getRGB();
-
- boolean darkBase = isDark(baseRGB);
- boolean darkBackground = isDark(background);
- if (darkBase && darkBackground)
- background = new RGB(255, 255, 255);
- else if (!darkBase && !darkBackground)
- background = new RGB(0, 0, 0);
-
- return getColor(interpolate(baseRGB, background, scale));
- }
-
- private Color getStrokeColor(AnnotationType annotationType, boolean temporary) {
- return getColor(annotationType, temporary ? 0.5 : 0.2);
- }
-
- private Color getFillColor(AnnotationType annotationType, boolean temporary) {
- return getColor(annotationType, temporary ? 0.9 : 0.6);
- }
-
- /**
- * @see IVerticalRulerInfo#getLineOfLastMouseButtonActivity()
- * @since 2.1
- */
- public int getLineOfLastMouseButtonActivity() {
- return fLastMouseButtonActivityLine;
- }
-
- /**
- * @see IVerticalRulerInfo#toDocumentLineNumber(int)
- * @since 2.1
- */
- public int toDocumentLineNumber(int y_coordinate) {
-
- if (fTextViewer == null || y_coordinate == -1)
- return -1;
-
- int[] lineNumbers = toLineNumbers(y_coordinate);
- int bestLine = findBestMatchingLineNumber(lineNumbers);
- if (bestLine == -1 && lineNumbers.length > 0)
- return lineNumbers[0];
- return bestLine;
- }
-
- /**
- * Returns the height of the problem rectangle.
- *
- * @return the height of the problem rectangle
- * @since 2.1
- */
- int getAnnotationHeight() {
- return fProblemHeight;
- }
-}