diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java index 2acf7ad1bcf..daca82416fe 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java @@ -44,9 +44,13 @@ import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewerExtension; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationRulerColumn; +import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.IVerticalRuler; +import org.eclipse.jface.text.source.IVerticalRulerColumn; +import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.util.PropertyChangeEvent; @@ -56,6 +60,7 @@ import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ST; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.VerifyKeyListener; @@ -67,10 +72,13 @@ import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.events.VerifyListener; import org.eclipse.swt.graphics.Color; 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.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorActionBarContributor; import org.eclipse.ui.IEditorInput; @@ -102,6 +110,7 @@ import org.eclipse.cdt.internal.ui.CPlugin; import org.eclipse.cdt.internal.ui.IContextMenuConstants; import org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration; import org.eclipse.cdt.internal.ui.text.CTextTools; +import org.eclipse.cdt.internal.ui.text.IColorManager; import org.eclipse.cdt.ui.ICDTConstants; import org.eclipse.cdt.ui.ICEditorContextMenuAction; import org.eclipse.cdt.ui.ICEditorRulerAction; @@ -147,6 +156,9 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList /** Listener to annotation model changes that updates the error tick in the tab image */ private CEditorErrorTickUpdater fCEditorErrorTickUpdater; + + /** The line number ruler column */ + private LineNumberRulerColumn fLineNumberRulerColumn; /* Preference key line color shading */ @@ -181,6 +193,14 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList public final static String SPACES_FOR_TABS= "spacesForTabs"; /** Preference key for linked position color */ public final static String LINKED_POSITION_COLOR= "linkedPositionColor"; //$NON-NLS-1$ + /** Preference key for shwoing the overview ruler */ + public final static String OVERVIEW_RULER= "overviewRuler"; //$NON-NLS-1$ + + /** Preference key for showing the line number ruler */ + public final static String LINE_NUMBER_RULER= "lineNumberRuler"; //$NON-NLS-1$ + /** Preference key for the foreground color of the line numbers */ + public final static String LINE_NUMBER_COLOR= "lineNumberColor"; //$NON-NLS-1$ + /** * Default constructor. @@ -459,6 +479,29 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList setBracketHighlightingStyle(); return; } + if (LINE_NUMBER_RULER.equals(property)) { + if (isLineNumberRulerVisible()) + showLineNumberRuler(); + else + hideLineNumberRuler(); + return; + } + + if (fLineNumberRulerColumn != null && + (LINE_NUMBER_COLOR.equals(property) || + PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property) || + PREFERENCE_COLOR_BACKGROUND.equals(property))) { + + initializeLineNumberRulerColumn(fLineNumberRulerColumn); + } + + if (OVERVIEW_RULER.equals(property)) { + if (isOverviewRulerVisible()) + showOverviewRuler(); + else + hideOverviewRuler(); + return; + } } } finally { @@ -1170,6 +1213,54 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList public final static String LANGUAGE_CPP= "CEditor.language.cpp"; public final static String LANGUAGE_C= "CEditor.language.c"; + + class AdaptedRulerLayout extends Layout { + + protected int fGap; + protected AdaptedSourceViewer fAdaptedSourceViewer; + + + protected AdaptedRulerLayout(int gap, AdaptedSourceViewer asv) { + fGap= gap; + fAdaptedSourceViewer= asv; + } + + protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { + Control[] children= composite.getChildren(); + Point s= children[children.length - 1].computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache); + if (fAdaptedSourceViewer.isVerticalRulerVisible()) + s.x += fAdaptedSourceViewer.getVerticalRuler().getWidth() + fGap; + return s; + } + + protected void layout(Composite composite, boolean flushCache) { + Rectangle clArea= composite.getClientArea(); + if (fAdaptedSourceViewer.isVerticalRulerVisible()) { + + StyledText textWidget= fAdaptedSourceViewer.getTextWidget(); + Rectangle trim= textWidget.computeTrim(0, 0, 0, 0); + int scrollbarHeight= trim.height; + + IVerticalRuler vr= fAdaptedSourceViewer.getVerticalRuler(); + int vrWidth=vr.getWidth(); + + int orWidth= 0; + if (fAdaptedSourceViewer.isOverviewRulerVisible()) { + OverviewRuler or= fAdaptedSourceViewer.getOverviewRuler(); + orWidth= or.getWidth(); + or.getControl().setBounds(clArea.width - orWidth, scrollbarHeight, orWidth, clArea.height - 3*scrollbarHeight); + } + + textWidget.setBounds(vrWidth + fGap, 0, clArea.width - vrWidth - orWidth - 2*fGap, clArea.height); + vr.getControl().setBounds(0, 0, vrWidth, clArea.height - scrollbarHeight); + + } else { + StyledText textWidget= fAdaptedSourceViewer.getTextWidget(); + textWidget.setBounds(0, 0, clArea.width, clArea.height); + } + } + }; + /** * Adapted source viewer for CEditor */ @@ -1178,31 +1269,31 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList private List fTextConverters; private String fDisplayLanguage; - //private OverviewRuler fOverviewRuler; - //private boolean fIsOverviewRulerVisible; + private OverviewRuler fOverviewRuler; + private boolean fIsOverviewRulerVisible; - //private IVerticalRuler fCachedVerticalRuler; - //private boolean fCachedIsVerticalRulerVisible; + private IVerticalRuler fCachedVerticalRuler; + private boolean fCachedIsVerticalRulerVisible; public AdaptedSourceViewer(Composite parent, IVerticalRuler ruler, int styles, String language) { super(parent, ruler, styles); fDisplayLanguage = language; - //fCachedVerticalRuler= ruler; - //fCachedIsVerticalRulerVisible= (ruler != null); - //fOverviewRuler= new OverviewRuler(VERTICAL_RULER_WIDTH); + fCachedVerticalRuler= ruler; + fCachedIsVerticalRulerVisible= (ruler != null); + fOverviewRuler= new OverviewRuler(VERTICAL_RULER_WIDTH); - //delayedCreateControl(parent, styles); + delayedCreateControl(parent, styles); } /* * @see ISourceViewer#showAnnotations(boolean) - * + */ public void showAnnotations(boolean show) { fCachedIsVerticalRulerVisible= (show && fCachedVerticalRuler != null); super.showAnnotations(show); - } */ + } /* public IContentAssistant getContentAssistant() { return fContentAssistant; @@ -1268,7 +1359,6 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList } } - /* public IVerticalRuler getVerticalRuler() { return fCachedVerticalRuler; } @@ -1283,7 +1373,7 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList /* * @see TextViewer#createControl(Composite, int) - * + */ protected void createControl(Composite parent, int styles) { // do nothing here } @@ -1320,15 +1410,15 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList public boolean isOverviewRulerVisible() { return fIsOverviewRulerVisible; - } */ + } /* * @see ISourceViewer#setDocument(IDocument, IAnnotationModel, int, int) - * + */ public void setDocument(IDocument document, IAnnotationModel annotationModel, int visibleRegionOffset, int visibleRegionLength) { super.setDocument(document, annotationModel, visibleRegionOffset, visibleRegionLength); fOverviewRuler.setModel(annotationModel); - } */ + } /** * Invalidates the current presentation by sending an initialization @@ -1639,4 +1729,107 @@ public class CEditor extends AbstractTextEditor implements ISelectionChangedList } return (ICEditorRulerAction[])rulerActions.toArray( new ICEditorRulerAction[0] ); } + + /** + * Creates a new line number ruler column that is appropriately initialized. + */ + protected IVerticalRulerColumn createLineNumberRulerColumn() { + fLineNumberRulerColumn= new LineNumberRulerColumn(); + initializeLineNumberRulerColumn(fLineNumberRulerColumn); + return fLineNumberRulerColumn; + } + + /* + * @see AbstractTextEditor#createVerticalRuler() + */ + protected IVerticalRuler createVerticalRuler() { + CompositeRuler ruler= new CompositeRuler(); + ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH)); + if (isLineNumberRulerVisible()) + ruler.addDecorator(1, createLineNumberRulerColumn()); + return ruler; + } + + /** + * Initializes the given line number ruler column from the preference store. + * @param rulerColumn the ruler column to be initialized + */ + protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) { + CTextTools textTools= CPlugin.getDefault().getTextTools(); + IColorManager manager= textTools.getColorManager(); + + IPreferenceStore store= getPreferenceStore(); + if (store != null) { + + RGB rgb= null; + // foreground color + if (store.contains(LINE_NUMBER_COLOR)) { + if (store.isDefault(LINE_NUMBER_COLOR)) + rgb= PreferenceConverter.getDefaultColor(store, LINE_NUMBER_COLOR); + else + rgb= PreferenceConverter.getColor(store, LINE_NUMBER_COLOR); + } + rulerColumn.setForeground(manager.getColor(rgb)); + + + rgb= null; + // background color + if (!store.getBoolean(PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) { + if (store.contains(PREFERENCE_COLOR_BACKGROUND)) { + if (store.isDefault(PREFERENCE_COLOR_BACKGROUND)) + rgb= PreferenceConverter.getDefaultColor(store, PREFERENCE_COLOR_BACKGROUND); + else + rgb= PreferenceConverter.getColor(store, PREFERENCE_COLOR_BACKGROUND); + } + } + rulerColumn.setBackground(manager.getColor(rgb)); + } + } + + /** + * Shows the line number ruler column. + */ + private void showLineNumberRuler() { + IVerticalRuler v= getVerticalRuler(); + if (v instanceof CompositeRuler) { + CompositeRuler c= (CompositeRuler) v; + c.addDecorator(1, createLineNumberRulerColumn()); + } + } + + /** + * Hides the line number ruler column. + */ + private void hideLineNumberRuler() { + IVerticalRuler v= getVerticalRuler(); + if (v instanceof CompositeRuler) { + CompositeRuler c= (CompositeRuler) v; + c.removeDecorator(1); + } + } + + /** + * Return whether the line number ruler column should be + * visible according to the preference store settings. + * @return true if the line numbers should be visible + */ + private boolean isLineNumberRulerVisible() { + IPreferenceStore store= getPreferenceStore(); + return store.getBoolean(LINE_NUMBER_RULER); + } + + private void showOverviewRuler() { + AdaptedSourceViewer asv= (AdaptedSourceViewer) getSourceViewer(); + asv.showOverviewRuler(); + } + + private void hideOverviewRuler() { + AdaptedSourceViewer asv= (AdaptedSourceViewer) getSourceViewer(); + asv.hideOverviewRuler(); + } + + private boolean isOverviewRulerVisible() { + IPreferenceStore store= getPreferenceStore(); + return store.getBoolean(OVERVIEW_RULER); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OverviewRuler.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OverviewRuler.java new file mode 100644 index 00000000000..cd1f74a1186 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OverviewRuler.java @@ -0,0 +1,498 @@ +package org.eclipse.cdt.internal.ui.editor; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + + + +import java.util.Iterator; + +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; + +import org.eclipse.cdt.internal.ui.CPlugin; +import org.eclipse.cdt.internal.ui.text.CTextTools; +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.Position; +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; + + + +/** + * + */ +public class OverviewRuler { + + /** + * 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 Iterator fIterator; + private int fType; + private Annotation fNext; + + public FilterIterator(int type) { + fType= type; + if (fModel != null) { + fIterator= fModel.getAnnotationIterator(); + skip(); + } + } + + private void skip() { + while (fIterator.hasNext()) { + fNext= (Annotation) fIterator.next(); + int type= getType(fNext); + if ((fType == ALL && type != UNKNOWN) || fType == type) + 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(); + } + }; + + + + /** Problem types */ + private static final int ALL= -1; + private static final int COMPILE_WARNING= 0; + private static final int COMPILE_ERROR= 1; + private static final int TEMPORARY= 2; + private static final int UNKNOWN= 4; + + /** Color table */ + private static final RGB[][] COLORS= new RGB[][] { + /* fill */ /* stroke */ + /* warning */ { new RGB(248, 218, 114), new RGB(139, 109, 7) }, + /* error */ { new RGB(255, 140, 140), new RGB(255, 0 ,0) }, + /* temp */ { new RGB(240, 230, 230), new RGB(200, 100, 100) } + }; + + /** drawing layers */ + private static final int[] LAYERS= new int[] { COMPILE_WARNING, TEMPORARY, COMPILE_ERROR }; + + 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; + + + /** + * 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; + } + + private int getType(Annotation annotation) { + if (annotation instanceof IProblemAnnotation) { + IProblemAnnotation pa= (IProblemAnnotation) annotation; + //if (!pa.isRelevant()) + // return UNKNOWN; + if (pa.isTemporaryProblem()) + return TEMPORARY; + if (pa.isError()) + return COMPILE_ERROR; + if (pa.isWarning()) + return COMPILE_WARNING; + } + + return UNKNOWN; + } + + 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; + } + } + + /** + * 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); + doPaint(gc); + } finally { + gc.dispose(); + } + + dest.drawImage(fBuffer, 0, 0); + } + + private Color getColor(RGB rgb) { + CTextTools textTools= CPlugin.getDefault().getTextTools(); + return textTools.getColorManager().getColor(rgb); + } + + 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(); + + Point size= fCanvas.getSize(); + int writable= maxLines * textWidget.getLineHeight(); + if (size.y > writable) + size.y= writable; + + for (int l= 0 ; l < LAYERS.length; l++) { + + Iterator e= new FilterIterator(LAYERS[l]); + Color fill= getColor(COLORS[LAYERS[l]][0]); + Color stroke= getColor(COLORS[LAYERS[l]][1]); + + for (int i= 0; e.hasNext(); i++) { + + Annotation a= (Annotation) e.next(); + Position p= fModel.getPosition(a); + + if (!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 { + + int startLine= textWidget.getLineAtOffset(problemOffset - visible.getOffset()); + yy= (startLine * size.y) / maxLines; + + if (PROBLEM_HEIGHT_SCALABLE) { + int numbersOfLines= document.getNumberOfLines(problemOffset, problemLength); + hh= (numbersOfLines * size.y) / maxLines; + if (hh < PROBLEM_HEIGHT_MIN) + hh= PROBLEM_HEIGHT_MIN; + } + + 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) { + + IRegion visible= fTextViewer.getVisibleRegion(); + int lineNumber= 0; + try { + lineNumber= fTextViewer.getDocument().getLineOfOffset(visible.getOffset()); + } catch (BadLocationException x) { + } + + StyledText textWidget= fTextViewer.getTextWidget(); + int maxLines= textWidget.getContent().getLineCount(); + + Point size= fCanvas.getSize(); + int writable= maxLines * textWidget.getLineHeight(); + if (size.y > writable) + size.y= writable; + + int[] lines= new int[2]; + + int pixel= Math.max(y_coordinate - 1, 0); + lines[0]= lineNumber + (pixel * maxLines) / size.y; + + pixel= Math.min(size.y, y_coordinate + 1); + lines[1]= lineNumber + (pixel * maxLines) / size.y; + + return lines; + } + + private Position getProblemPositionAt(int[] lineNumbers) { + + 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(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; + } + + 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(); + } + } + + 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; + } + } + } +}