Mercurial > projects > dwt-addons
comparison dwtx/jface/text/source/OverviewRuler.d @ 129:eb30df5ca28b
Added JFace Text sources
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 23 Aug 2008 19:10:48 +0200 |
parents | |
children | c4fb132a086c |
comparison
equal
deleted
inserted
replaced
128:8df1d4193877 | 129:eb30df5ca28b |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.text.source.OverviewRuler; | |
14 | |
15 import dwt.dwthelper.utils; | |
16 | |
17 import java.util.ArrayList; | |
18 import java.util.HashMap; | |
19 import java.util.HashSet; | |
20 import java.util.Iterator; | |
21 import java.util.List; | |
22 import java.util.Map; | |
23 import java.util.Set; | |
24 | |
25 import dwt.DWT; | |
26 import dwt.custom.StyledText; | |
27 import dwt.events.DisposeEvent; | |
28 import dwt.events.DisposeListener; | |
29 import dwt.events.MouseAdapter; | |
30 import dwt.events.MouseEvent; | |
31 import dwt.events.MouseMoveListener; | |
32 import dwt.events.MouseTrackAdapter; | |
33 import dwt.events.PaintEvent; | |
34 import dwt.events.PaintListener; | |
35 import dwt.graphics.Color; | |
36 import dwt.graphics.Cursor; | |
37 import dwt.graphics.GC; | |
38 import dwt.graphics.Image; | |
39 import dwt.graphics.Point; | |
40 import dwt.graphics.RGB; | |
41 import dwt.graphics.Rectangle; | |
42 import dwt.widgets.Canvas; | |
43 import dwt.widgets.Composite; | |
44 import dwt.widgets.Control; | |
45 import dwt.widgets.Display; | |
46 import dwtx.jface.text.BadLocationException; | |
47 import dwtx.jface.text.IDocument; | |
48 import dwtx.jface.text.IRegion; | |
49 import dwtx.jface.text.ITextListener; | |
50 import dwtx.jface.text.ITextViewer; | |
51 import dwtx.jface.text.ITextViewerExtension5; | |
52 import dwtx.jface.text.JFaceTextUtil; | |
53 import dwtx.jface.text.Position; | |
54 import dwtx.jface.text.Region; | |
55 import dwtx.jface.text.TextEvent; | |
56 import dwtx.jface.text.source.projection.AnnotationBag; | |
57 | |
58 | |
59 /** | |
60 * Ruler presented next to a source viewer showing all annotations of the | |
61 * viewer's annotation model in a compact format. The ruler has the same height | |
62 * as the source viewer. | |
63 * <p> | |
64 * Clients usually instantiate and configure objects of this class.</p> | |
65 * | |
66 * @since 2.1 | |
67 */ | |
68 public class OverviewRuler : IOverviewRuler { | |
69 | |
70 /** | |
71 * Internal listener class. | |
72 */ | |
73 class InternalListener : ITextListener, IAnnotationModelListener, IAnnotationModelListenerExtension { | |
74 | |
75 /* | |
76 * @see ITextListener#textChanged | |
77 */ | |
78 public void textChanged(TextEvent e) { | |
79 if (fTextViewer !is null && e.getDocumentEvent() is null && e.getViewerRedrawState()) { | |
80 // handle only changes of visible document | |
81 redraw(); | |
82 } | |
83 } | |
84 | |
85 /* | |
86 * @see IAnnotationModelListener#modelChanged(IAnnotationModel) | |
87 */ | |
88 public void modelChanged(IAnnotationModel model) { | |
89 update(); | |
90 } | |
91 | |
92 /* | |
93 * @see dwtx.jface.text.source.IAnnotationModelListenerExtension#modelChanged(dwtx.jface.text.source.AnnotationModelEvent) | |
94 * @since 3.3 | |
95 */ | |
96 public void modelChanged(AnnotationModelEvent event) { | |
97 if (!event.isValid()) | |
98 return; | |
99 | |
100 if (event.isWorldChange()) { | |
101 update(); | |
102 return; | |
103 } | |
104 | |
105 Annotation[] annotations= event.getAddedAnnotations(); | |
106 int length= annotations.length; | |
107 for (int i= 0; i < length; i++) { | |
108 if (!skip(annotations[i].getType())) { | |
109 update(); | |
110 return; | |
111 } | |
112 } | |
113 | |
114 annotations= event.getRemovedAnnotations(); | |
115 length= annotations.length; | |
116 for (int i= 0; i < length; i++) { | |
117 if (!skip(annotations[i].getType())) { | |
118 update(); | |
119 return; | |
120 } | |
121 } | |
122 | |
123 annotations= event.getChangedAnnotations(); | |
124 length= annotations.length; | |
125 for (int i= 0; i < length; i++) { | |
126 if (!skip(annotations[i].getType())) { | |
127 update(); | |
128 return; | |
129 } | |
130 } | |
131 | |
132 } | |
133 } | |
134 | |
135 /** | |
136 * Enumerates the annotations of a specified type and characteristics | |
137 * of the associated annotation model. | |
138 */ | |
139 class FilterIterator : Iterator { | |
140 | |
141 final static int TEMPORARY= 1 << 1; | |
142 final static int PERSISTENT= 1 << 2; | |
143 final static int IGNORE_BAGS= 1 << 3; | |
144 | |
145 private Iterator fIterator; | |
146 private Object fType; | |
147 private Annotation fNext; | |
148 private int fStyle; | |
149 | |
150 /** | |
151 * Creates a new filter iterator with the given specification. | |
152 * | |
153 * @param annotationType the annotation type | |
154 * @param style the style | |
155 */ | |
156 public FilterIterator(Object annotationType, int style) { | |
157 fType= annotationType; | |
158 fStyle= style; | |
159 if (fModel !is null) { | |
160 fIterator= fModel.getAnnotationIterator(); | |
161 skip(); | |
162 } | |
163 } | |
164 | |
165 /** | |
166 * Creates a new filter iterator with the given specification. | |
167 * | |
168 * @param annotationType the annotation type | |
169 * @param style the style | |
170 * @param iterator the iterator | |
171 */ | |
172 public FilterIterator(Object annotationType, int style, Iterator iterator) { | |
173 fType= annotationType; | |
174 fStyle= style; | |
175 fIterator= iterator; | |
176 skip(); | |
177 } | |
178 | |
179 private void skip() { | |
180 | |
181 bool temp= (fStyle & TEMPORARY) !is 0; | |
182 bool pers= (fStyle & PERSISTENT) !is 0; | |
183 bool ignr= (fStyle & IGNORE_BAGS) !is 0; | |
184 | |
185 while (fIterator.hasNext()) { | |
186 Annotation next= (Annotation) fIterator.next(); | |
187 | |
188 if (next.isMarkedDeleted()) | |
189 continue; | |
190 | |
191 if (ignr && (next instanceof AnnotationBag)) | |
192 continue; | |
193 | |
194 fNext= next; | |
195 Object annotationType= next.getType(); | |
196 if (fType is null || fType.equals(annotationType) || !fConfiguredAnnotationTypes.contains(annotationType) && isSubtype(annotationType)) { | |
197 if (temp && pers) return; | |
198 if (pers && next.isPersistent()) return; | |
199 if (temp && !next.isPersistent()) return; | |
200 } | |
201 } | |
202 fNext= null; | |
203 } | |
204 | |
205 private bool isSubtype(Object annotationType) { | |
206 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { | |
207 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; | |
208 return extension.isSubtype(annotationType, fType); | |
209 } | |
210 return fType.equals(annotationType); | |
211 } | |
212 | |
213 /* | |
214 * @see Iterator#hasNext() | |
215 */ | |
216 public bool hasNext() { | |
217 return fNext !is null; | |
218 } | |
219 /* | |
220 * @see Iterator#next() | |
221 */ | |
222 public Object next() { | |
223 try { | |
224 return fNext; | |
225 } finally { | |
226 if (fIterator !is null) | |
227 skip(); | |
228 } | |
229 } | |
230 /* | |
231 * @see Iterator#remove() | |
232 */ | |
233 public void remove() { | |
234 throw new UnsupportedOperationException(); | |
235 } | |
236 } | |
237 | |
238 /** | |
239 * The painter of the overview ruler's header. | |
240 */ | |
241 class HeaderPainter : PaintListener { | |
242 | |
243 private Color fIndicatorColor; | |
244 private Color fSeparatorColor; | |
245 | |
246 /** | |
247 * Creates a new header painter. | |
248 */ | |
249 public HeaderPainter() { | |
250 fSeparatorColor= fHeader.getDisplay().getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW); | |
251 } | |
252 | |
253 /** | |
254 * Sets the header color. | |
255 * | |
256 * @param color the header color | |
257 */ | |
258 public void setColor(Color color) { | |
259 fIndicatorColor= color; | |
260 } | |
261 | |
262 private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topLeft, Color bottomRight) { | |
263 gc.setForeground(topLeft is null ? fSeparatorColor : topLeft); | |
264 gc.drawLine(x, y, x + w -1, y); | |
265 gc.drawLine(x, y, x, y + h -1); | |
266 | |
267 gc.setForeground(bottomRight is null ? fSeparatorColor : bottomRight); | |
268 gc.drawLine(x + w, y, x + w, y + h); | |
269 gc.drawLine(x, y + h, x + w, y + h); | |
270 } | |
271 | |
272 public void paintControl(PaintEvent e) { | |
273 if (fIndicatorColor is null) | |
274 return; | |
275 | |
276 Point s= fHeader.getSize(); | |
277 | |
278 e.gc.setBackground(fIndicatorColor); | |
279 Rectangle r= new Rectangle(INSET, (s.y - (2*ANNOTATION_HEIGHT)) / 2, s.x - (2*INSET), 2*ANNOTATION_HEIGHT); | |
280 e.gc.fillRectangle(r); | |
281 Display d= fHeader.getDisplay(); | |
282 if (d !is null) | |
283 // drawBevelRect(e.gc, r.x, r.y, r.width -1, r.height -1, d.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW), d.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW)); | |
284 drawBevelRect(e.gc, r.x, r.y, r.width -1, r.height -1, null, null); | |
285 | |
286 e.gc.setForeground(fSeparatorColor); | |
287 e.gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance | |
288 e.gc.drawLine(0, s.y -1, s.x -1, s.y -1); | |
289 } | |
290 } | |
291 | |
292 private static final int INSET= 2; | |
293 private static final int ANNOTATION_HEIGHT= 4; | |
294 private static bool ANNOTATION_HEIGHT_SCALABLE= true; | |
295 | |
296 | |
297 /** The model of the overview ruler */ | |
298 private IAnnotationModel fModel; | |
299 /** The view to which this ruler is connected */ | |
300 private ITextViewer fTextViewer; | |
301 /** The ruler's canvas */ | |
302 private Canvas fCanvas; | |
303 /** The ruler's header */ | |
304 private Canvas fHeader; | |
305 /** The buffer for double buffering */ | |
306 private Image fBuffer; | |
307 /** The internal listener */ | |
308 private InternalListener fInternalListener= new InternalListener(); | |
309 /** The width of this vertical ruler */ | |
310 private int fWidth; | |
311 /** The hit detection cursor */ | |
312 private Cursor fHitDetectionCursor; | |
313 /** The last cursor */ | |
314 private Cursor fLastCursor; | |
315 /** The line of the last mouse button activity */ | |
316 private int fLastMouseButtonActivityLine= -1; | |
317 /** The actual annotation height */ | |
318 private int fAnnotationHeight= -1; | |
319 /** The annotation access */ | |
320 private IAnnotationAccess fAnnotationAccess; | |
321 /** The header painter */ | |
322 private HeaderPainter fHeaderPainter; | |
323 /** | |
324 * The list of annotation types to be shown in this ruler. | |
325 * @since 3.0 | |
326 */ | |
327 private Set fConfiguredAnnotationTypes= new HashSet(); | |
328 /** | |
329 * The list of annotation types to be shown in the header of this ruler. | |
330 * @since 3.0 | |
331 */ | |
332 private Set fConfiguredHeaderAnnotationTypes= new HashSet(); | |
333 /** The mapping between annotation types and colors */ | |
334 private Map fAnnotationTypes2Colors= new HashMap(); | |
335 /** The color manager */ | |
336 private ISharedTextColors fSharedTextColors; | |
337 /** | |
338 * All available annotation types sorted by layer. | |
339 * | |
340 * @since 3.0 | |
341 */ | |
342 private List fAnnotationsSortedByLayer= new ArrayList(); | |
343 /** | |
344 * All available layers sorted by layer. | |
345 * This list may contain duplicates. | |
346 * @since 3.0 | |
347 */ | |
348 private List fLayersSortedByLayer= new ArrayList(); | |
349 /** | |
350 * Map of allowed annotation types. | |
351 * An allowed annotation type maps to <code>true</code>, a disallowed | |
352 * to <code>false</code>. | |
353 * @since 3.0 | |
354 */ | |
355 private Map fAllowedAnnotationTypes= new HashMap(); | |
356 /** | |
357 * Map of allowed header annotation types. | |
358 * An allowed annotation type maps to <code>true</code>, a disallowed | |
359 * to <code>false</code>. | |
360 * @since 3.0 | |
361 */ | |
362 private Map fAllowedHeaderAnnotationTypes= new HashMap(); | |
363 /** | |
364 * The cached annotations. | |
365 * @since 3.0 | |
366 */ | |
367 private List fCachedAnnotations= new ArrayList(); | |
368 | |
369 /** | |
370 * Redraw runnable lock | |
371 * @since 3.3 | |
372 */ | |
373 private Object fRunnableLock= new Object(); | |
374 /** | |
375 * Redraw runnable state | |
376 * @since 3.3 | |
377 */ | |
378 private bool fIsRunnablePosted= false; | |
379 /** | |
380 * Redraw runnable | |
381 * @since 3.3 | |
382 */ | |
383 private Runnable fRunnable= new Runnable() { | |
384 public void run() { | |
385 synchronized (fRunnableLock) { | |
386 fIsRunnablePosted= false; | |
387 } | |
388 redraw(); | |
389 updateHeader(); | |
390 } | |
391 }; | |
392 /** | |
393 * Tells whether temporary annotations are drawn with | |
394 * a separate color. This color will be computed by | |
395 * discoloring the original annotation color. | |
396 * | |
397 * @since 3.4 | |
398 */ | |
399 private bool fIsTemporaryAnnotationDiscolored; | |
400 | |
401 | |
402 /** | |
403 * Constructs a overview ruler of the given width using the given annotation access and the given | |
404 * color manager. | |
405 * <p><strong>Note:</strong> As of 3.4, temporary annotations are no longer discolored. | |
406 * Use {@link #OverviewRuler(IAnnotationAccess, int, ISharedTextColors, bool)} if you | |
407 * want to keep the old behavior.</p> | |
408 * | |
409 * @param annotationAccess the annotation access | |
410 * @param width the width of the vertical ruler | |
411 * @param sharedColors the color manager | |
412 */ | |
413 public OverviewRuler(IAnnotationAccess annotationAccess, int width, ISharedTextColors sharedColors) { | |
414 this(annotationAccess, width, sharedColors, false); | |
415 } | |
416 | |
417 /** | |
418 * Constructs a overview ruler of the given width using the given annotation | |
419 * access and the given color manager. | |
420 * | |
421 * @param annotationAccess the annotation access | |
422 * @param width the width of the vertical ruler | |
423 * @param sharedColors the color manager | |
424 * @param discolorTemporaryAnnotation <code>true</code> if temporary annotations should be discolored | |
425 * @since 3.4 | |
426 */ | |
427 public OverviewRuler(IAnnotationAccess annotationAccess, int width, ISharedTextColors sharedColors, bool discolorTemporaryAnnotation) { | |
428 fAnnotationAccess= annotationAccess; | |
429 fWidth= width; | |
430 fSharedTextColors= sharedColors; | |
431 fIsTemporaryAnnotationDiscolored= discolorTemporaryAnnotation; | |
432 } | |
433 | |
434 /* | |
435 * @see dwtx.jface.text.source.IVerticalRulerInfo#getControl() | |
436 */ | |
437 public Control getControl() { | |
438 return fCanvas; | |
439 } | |
440 | |
441 /* | |
442 * @see dwtx.jface.text.source.IVerticalRulerInfo#getWidth() | |
443 */ | |
444 public int getWidth() { | |
445 return fWidth; | |
446 } | |
447 | |
448 /* | |
449 * @see dwtx.jface.text.source.IVerticalRuler#setModel(dwtx.jface.text.source.IAnnotationModel) | |
450 */ | |
451 public void setModel(IAnnotationModel model) { | |
452 if (model !is fModel || model !is null) { | |
453 | |
454 if (fModel !is null) | |
455 fModel.removeAnnotationModelListener(fInternalListener); | |
456 | |
457 fModel= model; | |
458 | |
459 if (fModel !is null) | |
460 fModel.addAnnotationModelListener(fInternalListener); | |
461 | |
462 update(); | |
463 } | |
464 } | |
465 | |
466 /* | |
467 * @see dwtx.jface.text.source.IVerticalRuler#createControl(dwt.widgets.Composite, dwtx.jface.text.ITextViewer) | |
468 */ | |
469 public Control createControl(Composite parent, ITextViewer textViewer) { | |
470 | |
471 fTextViewer= textViewer; | |
472 | |
473 fHitDetectionCursor= new Cursor(parent.getDisplay(), DWT.CURSOR_HAND); | |
474 | |
475 fHeader= new Canvas(parent, DWT.NONE); | |
476 | |
477 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { | |
478 fHeader.addMouseTrackListener(new MouseTrackAdapter() { | |
479 /* | |
480 * @see dwt.events.MouseTrackAdapter#mouseHover(dwt.events.MouseEvent) | |
481 * @since 3.3 | |
482 */ | |
483 public void mouseEnter(MouseEvent e) { | |
484 updateHeaderToolTipText(); | |
485 } | |
486 }); | |
487 } | |
488 | |
489 fCanvas= new Canvas(parent, DWT.NO_BACKGROUND); | |
490 | |
491 fCanvas.addPaintListener(new PaintListener() { | |
492 public void paintControl(PaintEvent event) { | |
493 if (fTextViewer !is null) | |
494 doubleBufferPaint(event.gc); | |
495 } | |
496 }); | |
497 | |
498 fCanvas.addDisposeListener(new DisposeListener() { | |
499 public void widgetDisposed(DisposeEvent event) { | |
500 handleDispose(); | |
501 fTextViewer= null; | |
502 } | |
503 }); | |
504 | |
505 fCanvas.addMouseListener(new MouseAdapter() { | |
506 public void mouseDown(MouseEvent event) { | |
507 handleMouseDown(event); | |
508 } | |
509 }); | |
510 | |
511 fCanvas.addMouseMoveListener(new MouseMoveListener() { | |
512 public void mouseMove(MouseEvent event) { | |
513 handleMouseMove(event); | |
514 } | |
515 }); | |
516 | |
517 if (fTextViewer !is null) | |
518 fTextViewer.addTextListener(fInternalListener); | |
519 | |
520 return fCanvas; | |
521 } | |
522 | |
523 /** | |
524 * Disposes the ruler's resources. | |
525 */ | |
526 private void handleDispose() { | |
527 | |
528 if (fTextViewer !is null) { | |
529 fTextViewer.removeTextListener(fInternalListener); | |
530 fTextViewer= null; | |
531 } | |
532 | |
533 if (fModel !is null) | |
534 fModel.removeAnnotationModelListener(fInternalListener); | |
535 | |
536 if (fBuffer !is null) { | |
537 fBuffer.dispose(); | |
538 fBuffer= null; | |
539 } | |
540 | |
541 if (fHitDetectionCursor !is null) { | |
542 fHitDetectionCursor.dispose(); | |
543 fHitDetectionCursor= null; | |
544 } | |
545 | |
546 fConfiguredAnnotationTypes.clear(); | |
547 fAllowedAnnotationTypes.clear(); | |
548 fConfiguredHeaderAnnotationTypes.clear(); | |
549 fAllowedHeaderAnnotationTypes.clear(); | |
550 fAnnotationTypes2Colors.clear(); | |
551 fAnnotationsSortedByLayer.clear(); | |
552 fLayersSortedByLayer.clear(); | |
553 } | |
554 | |
555 /** | |
556 * Double buffer drawing. | |
557 * | |
558 * @param dest the GC to draw into | |
559 */ | |
560 private void doubleBufferPaint(GC dest) { | |
561 | |
562 Point size= fCanvas.getSize(); | |
563 | |
564 if (size.x <= 0 || size.y <= 0) | |
565 return; | |
566 | |
567 if (fBuffer !is null) { | |
568 Rectangle r= fBuffer.getBounds(); | |
569 if (r.width !is size.x || r.height !is size.y) { | |
570 fBuffer.dispose(); | |
571 fBuffer= null; | |
572 } | |
573 } | |
574 if (fBuffer is null) | |
575 fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); | |
576 | |
577 GC gc= new GC(fBuffer); | |
578 try { | |
579 gc.setBackground(fCanvas.getBackground()); | |
580 gc.fillRectangle(0, 0, size.x, size.y); | |
581 | |
582 cacheAnnotations(); | |
583 | |
584 if (fTextViewer instanceof ITextViewerExtension5) | |
585 doPaint1(gc); | |
586 else | |
587 doPaint(gc); | |
588 | |
589 } finally { | |
590 gc.dispose(); | |
591 } | |
592 | |
593 dest.drawImage(fBuffer, 0, 0); | |
594 } | |
595 | |
596 /** | |
597 * Draws this overview ruler. | |
598 * | |
599 * @param gc the GC to draw into | |
600 */ | |
601 private void doPaint(GC gc) { | |
602 | |
603 Rectangle r= new Rectangle(0, 0, 0, 0); | |
604 int yy, hh= ANNOTATION_HEIGHT; | |
605 | |
606 IDocument document= fTextViewer.getDocument(); | |
607 IRegion visible= fTextViewer.getVisibleRegion(); | |
608 | |
609 StyledText textWidget= fTextViewer.getTextWidget(); | |
610 int maxLines= textWidget.getLineCount(); | |
611 | |
612 Point size= fCanvas.getSize(); | |
613 int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); | |
614 | |
615 if (size.y > writable) | |
616 size.y= Math.max(writable - fHeader.getSize().y, 0); | |
617 | |
618 for (Iterator iterator= fAnnotationsSortedByLayer.iterator(); iterator.hasNext();) { | |
619 Object annotationType= iterator.next(); | |
620 | |
621 if (skip(annotationType)) | |
622 continue; | |
623 | |
624 int[] style= new int[] { FilterIterator.PERSISTENT, FilterIterator.TEMPORARY }; | |
625 for (int t=0; t < style.length; t++) { | |
626 | |
627 Iterator e= new FilterIterator(annotationType, style[t], fCachedAnnotations.iterator()); | |
628 Color fill= getFillColor(annotationType, style[t] is FilterIterator.TEMPORARY); | |
629 Color stroke= getStrokeColor(annotationType, style[t] is FilterIterator.TEMPORARY); | |
630 | |
631 for (int i= 0; e.hasNext(); i++) { | |
632 | |
633 Annotation a= (Annotation) e.next(); | |
634 Position p= fModel.getPosition(a); | |
635 | |
636 if (p is null || !p.overlapsWith(visible.getOffset(), visible.getLength())) | |
637 continue; | |
638 | |
639 int annotationOffset= Math.max(p.getOffset(), visible.getOffset()); | |
640 int annotationEnd= Math.min(p.getOffset() + p.getLength(), visible.getOffset() + visible.getLength()); | |
641 int annotationLength= annotationEnd - annotationOffset; | |
642 | |
643 try { | |
644 if (ANNOTATION_HEIGHT_SCALABLE) { | |
645 int numbersOfLines= document.getNumberOfLines(annotationOffset, annotationLength); | |
646 // don't count empty trailing lines | |
647 IRegion lastLine= document.getLineInformationOfOffset(annotationOffset + annotationLength); | |
648 if (lastLine.getOffset() is annotationOffset + annotationLength) { | |
649 numbersOfLines -= 2; | |
650 hh= (numbersOfLines * size.y) / maxLines + ANNOTATION_HEIGHT; | |
651 if (hh < ANNOTATION_HEIGHT) | |
652 hh= ANNOTATION_HEIGHT; | |
653 } else | |
654 hh= ANNOTATION_HEIGHT; | |
655 } | |
656 fAnnotationHeight= hh; | |
657 | |
658 int startLine= textWidget.getLineAtOffset(annotationOffset - visible.getOffset()); | |
659 yy= Math.min((startLine * size.y) / maxLines, size.y - hh); | |
660 | |
661 if (fill !is null) { | |
662 gc.setBackground(fill); | |
663 gc.fillRectangle(INSET, yy, size.x-(2*INSET), hh); | |
664 } | |
665 | |
666 if (stroke !is null) { | |
667 gc.setForeground(stroke); | |
668 r.x= INSET; | |
669 r.y= yy; | |
670 r.width= size.x - (2 * INSET); | |
671 r.height= hh; | |
672 gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance | |
673 gc.drawRectangle(r); | |
674 } | |
675 } catch (BadLocationException x) { | |
676 } | |
677 } | |
678 } | |
679 } | |
680 } | |
681 | |
682 private void cacheAnnotations() { | |
683 fCachedAnnotations.clear(); | |
684 if (fModel !is null) { | |
685 Iterator iter= fModel.getAnnotationIterator(); | |
686 while (iter.hasNext()) { | |
687 Annotation annotation= (Annotation) iter.next(); | |
688 | |
689 if (annotation.isMarkedDeleted()) | |
690 continue; | |
691 | |
692 if (skip(annotation.getType())) | |
693 continue; | |
694 | |
695 fCachedAnnotations.add(annotation); | |
696 } | |
697 } | |
698 } | |
699 | |
700 /** | |
701 * Draws this overview ruler. Uses <code>ITextViewerExtension5</code> for | |
702 * its implementation. Will replace <code>doPaint(GC)</code>. | |
703 * | |
704 * @param gc the GC to draw into | |
705 */ | |
706 private void doPaint1(GC gc) { | |
707 | |
708 Rectangle r= new Rectangle(0, 0, 0, 0); | |
709 int yy, hh= ANNOTATION_HEIGHT; | |
710 | |
711 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; | |
712 IDocument document= fTextViewer.getDocument(); | |
713 StyledText textWidget= fTextViewer.getTextWidget(); | |
714 | |
715 int maxLines= textWidget.getLineCount(); | |
716 Point size= fCanvas.getSize(); | |
717 int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); | |
718 if (size.y > writable) | |
719 size.y= Math.max(writable - fHeader.getSize().y, 0); | |
720 | |
721 for (Iterator iterator= fAnnotationsSortedByLayer.iterator(); iterator.hasNext();) { | |
722 Object annotationType= iterator.next(); | |
723 | |
724 if (skip(annotationType)) | |
725 continue; | |
726 | |
727 int[] style= new int[] { FilterIterator.PERSISTENT, FilterIterator.TEMPORARY }; | |
728 for (int t=0; t < style.length; t++) { | |
729 | |
730 Iterator e= new FilterIterator(annotationType, style[t], fCachedAnnotations.iterator()); | |
731 Color fill= getFillColor(annotationType, style[t] is FilterIterator.TEMPORARY); | |
732 Color stroke= getStrokeColor(annotationType, style[t] is FilterIterator.TEMPORARY); | |
733 | |
734 for (int i= 0; e.hasNext(); i++) { | |
735 | |
736 Annotation a= (Annotation) e.next(); | |
737 Position p= fModel.getPosition(a); | |
738 | |
739 if (p is null) | |
740 continue; | |
741 | |
742 IRegion widgetRegion= extension.modelRange2WidgetRange(new Region(p.getOffset(), p.getLength())); | |
743 if (widgetRegion is null) | |
744 continue; | |
745 | |
746 try { | |
747 if (ANNOTATION_HEIGHT_SCALABLE) { | |
748 int numbersOfLines= document.getNumberOfLines(p.getOffset(), p.getLength()); | |
749 // don't count empty trailing lines | |
750 IRegion lastLine= document.getLineInformationOfOffset(p.getOffset() + p.getLength()); | |
751 if (lastLine.getOffset() is p.getOffset() + p.getLength()) { | |
752 numbersOfLines -= 2; | |
753 hh= (numbersOfLines * size.y) / maxLines + ANNOTATION_HEIGHT; | |
754 if (hh < ANNOTATION_HEIGHT) | |
755 hh= ANNOTATION_HEIGHT; | |
756 } else | |
757 hh= ANNOTATION_HEIGHT; | |
758 } | |
759 fAnnotationHeight= hh; | |
760 | |
761 int startLine= textWidget.getLineAtOffset(widgetRegion.getOffset()); | |
762 yy= Math.min((startLine * size.y) / maxLines, size.y - hh); | |
763 | |
764 if (fill !is null) { | |
765 gc.setBackground(fill); | |
766 gc.fillRectangle(INSET, yy, size.x-(2*INSET), hh); | |
767 } | |
768 | |
769 if (stroke !is null) { | |
770 gc.setForeground(stroke); | |
771 r.x= INSET; | |
772 r.y= yy; | |
773 r.width= size.x - (2 * INSET); | |
774 r.height= hh; | |
775 gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance | |
776 gc.drawRectangle(r); | |
777 } | |
778 } catch (BadLocationException x) { | |
779 } | |
780 } | |
781 } | |
782 } | |
783 } | |
784 | |
785 /* | |
786 * @see dwtx.jface.text.source.IVerticalRuler#update() | |
787 */ | |
788 public void update() { | |
789 if (fCanvas !is null && !fCanvas.isDisposed()) { | |
790 Display d= fCanvas.getDisplay(); | |
791 if (d !is null) { | |
792 synchronized (fRunnableLock) { | |
793 if (fIsRunnablePosted) | |
794 return; | |
795 fIsRunnablePosted= true; | |
796 } | |
797 d.asyncExec(fRunnable); | |
798 } | |
799 } | |
800 } | |
801 | |
802 /** | |
803 * Redraws the overview ruler. | |
804 */ | |
805 private void redraw() { | |
806 if (fTextViewer is null || fModel is null) | |
807 return; | |
808 | |
809 if (fCanvas !is null && !fCanvas.isDisposed()) { | |
810 GC gc= new GC(fCanvas); | |
811 doubleBufferPaint(gc); | |
812 gc.dispose(); | |
813 } | |
814 } | |
815 | |
816 /** | |
817 * Translates a given y-coordinate of this ruler into the corresponding | |
818 * document lines. The number of lines depends on the concrete scaling | |
819 * given as the ration between the height of this ruler and the length | |
820 * of the document. | |
821 * | |
822 * @param y_coordinate the y-coordinate | |
823 * @return the corresponding document lines | |
824 */ | |
825 private int[] toLineNumbers(int y_coordinate) { | |
826 | |
827 StyledText textWidget= fTextViewer.getTextWidget(); | |
828 int maxLines= textWidget.getContent().getLineCount(); | |
829 | |
830 int rulerLength= fCanvas.getSize().y; | |
831 int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); | |
832 | |
833 if (rulerLength > writable) | |
834 rulerLength= Math.max(writable - fHeader.getSize().y, 0); | |
835 | |
836 if (y_coordinate >= writable || y_coordinate >= rulerLength) | |
837 return new int[] {-1, -1}; | |
838 | |
839 int[] lines= new int[2]; | |
840 | |
841 int pixel0= Math.max(y_coordinate - 1, 0); | |
842 int pixel1= Math.min(rulerLength, y_coordinate + 1); | |
843 rulerLength= Math.max(rulerLength, 1); | |
844 | |
845 lines[0]= (pixel0 * maxLines) / rulerLength; | |
846 lines[1]= (pixel1 * maxLines) / rulerLength; | |
847 | |
848 if (fTextViewer instanceof ITextViewerExtension5) { | |
849 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; | |
850 lines[0]= extension.widgetLine2ModelLine(lines[0]); | |
851 lines[1]= extension.widgetLine2ModelLine(lines[1]); | |
852 } else { | |
853 try { | |
854 IRegion visible= fTextViewer.getVisibleRegion(); | |
855 int lineNumber= fTextViewer.getDocument().getLineOfOffset(visible.getOffset()); | |
856 lines[0] += lineNumber; | |
857 lines[1] += lineNumber; | |
858 } catch (BadLocationException x) { | |
859 } | |
860 } | |
861 | |
862 return lines; | |
863 } | |
864 | |
865 /** | |
866 * Returns the position of the first annotation found in the given line range. | |
867 * | |
868 * @param lineNumbers the line range | |
869 * @return the position of the first found annotation | |
870 */ | |
871 private Position getAnnotationPosition(int[] lineNumbers) { | |
872 if (lineNumbers[0] is -1) | |
873 return null; | |
874 | |
875 Position found= null; | |
876 | |
877 try { | |
878 IDocument d= fTextViewer.getDocument(); | |
879 IRegion line= d.getLineInformation(lineNumbers[0]); | |
880 | |
881 int start= line.getOffset(); | |
882 | |
883 line= d.getLineInformation(lineNumbers[lineNumbers.length - 1]); | |
884 int end= line.getOffset() + line.getLength(); | |
885 | |
886 for (int i= fAnnotationsSortedByLayer.size() -1; i >= 0; i--) { | |
887 | |
888 Object annotationType= fAnnotationsSortedByLayer.get(i); | |
889 | |
890 Iterator e= new FilterIterator(annotationType, FilterIterator.PERSISTENT | FilterIterator.TEMPORARY); | |
891 while (e.hasNext() && found is null) { | |
892 Annotation a= (Annotation) e.next(); | |
893 if (a.isMarkedDeleted()) | |
894 continue; | |
895 | |
896 if (skip(a.getType())) | |
897 continue; | |
898 | |
899 Position p= fModel.getPosition(a); | |
900 if (p is null) | |
901 continue; | |
902 | |
903 int posOffset= p.getOffset(); | |
904 int posEnd= posOffset + p.getLength(); | |
905 IRegion region= d.getLineInformationOfOffset(posEnd); | |
906 // trailing empty lines don't count | |
907 if (posEnd > posOffset && region.getOffset() is posEnd) { | |
908 posEnd--; | |
909 region= d.getLineInformationOfOffset(posEnd); | |
910 } | |
911 | |
912 if (posOffset <= end && posEnd >= start) | |
913 found= p; | |
914 } | |
915 } | |
916 } catch (BadLocationException x) { | |
917 } | |
918 | |
919 return found; | |
920 } | |
921 | |
922 /** | |
923 * Returns the line which corresponds best to one of | |
924 * the underlying annotations at the given y-coordinate. | |
925 * | |
926 * @param lineNumbers the line numbers | |
927 * @return the best matching line or <code>-1</code> if no such line can be found | |
928 */ | |
929 private int findBestMatchingLineNumber(int[] lineNumbers) { | |
930 if (lineNumbers is null || lineNumbers.length < 1) | |
931 return -1; | |
932 | |
933 try { | |
934 Position pos= getAnnotationPosition(lineNumbers); | |
935 if (pos is null) | |
936 return -1; | |
937 return fTextViewer.getDocument().getLineOfOffset(pos.getOffset()); | |
938 } catch (BadLocationException ex) { | |
939 return -1; | |
940 } | |
941 } | |
942 | |
943 /** | |
944 * Handles mouse clicks. | |
945 * | |
946 * @param event the mouse button down event | |
947 */ | |
948 private void handleMouseDown(MouseEvent event) { | |
949 if (fTextViewer !is null) { | |
950 int[] lines= toLineNumbers(event.y); | |
951 Position p= getAnnotationPosition(lines); | |
952 if (p is null && event.button is 1) { | |
953 try { | |
954 p= new Position(fTextViewer.getDocument().getLineInformation(lines[0]).getOffset(), 0); | |
955 } catch (BadLocationException e) { | |
956 // do nothing | |
957 } | |
958 } | |
959 if (p !is null) { | |
960 fTextViewer.revealRange(p.getOffset(), p.getLength()); | |
961 fTextViewer.setSelectedRange(p.getOffset(), p.getLength()); | |
962 } | |
963 fTextViewer.getTextWidget().setFocus(); | |
964 } | |
965 fLastMouseButtonActivityLine= toDocumentLineNumber(event.y); | |
966 } | |
967 | |
968 /** | |
969 * Handles mouse moves. | |
970 * | |
971 * @param event the mouse move event | |
972 */ | |
973 private void handleMouseMove(MouseEvent event) { | |
974 if (fTextViewer !is null) { | |
975 int[] lines= toLineNumbers(event.y); | |
976 Position p= getAnnotationPosition(lines); | |
977 Cursor cursor= (p !is null ? fHitDetectionCursor : null); | |
978 if (cursor !is fLastCursor) { | |
979 fCanvas.setCursor(cursor); | |
980 fLastCursor= cursor; | |
981 } | |
982 } | |
983 } | |
984 | |
985 /* | |
986 * @see dwtx.jface.text.source.IOverviewRuler#addAnnotationType(java.lang.Object) | |
987 */ | |
988 public void addAnnotationType(Object annotationType) { | |
989 fConfiguredAnnotationTypes.add(annotationType); | |
990 fAllowedAnnotationTypes.clear(); | |
991 } | |
992 | |
993 /* | |
994 * @see dwtx.jface.text.source.IOverviewRuler#removeAnnotationType(java.lang.Object) | |
995 */ | |
996 public void removeAnnotationType(Object annotationType) { | |
997 fConfiguredAnnotationTypes.remove(annotationType); | |
998 fAllowedAnnotationTypes.clear(); | |
999 } | |
1000 | |
1001 /* | |
1002 * @see dwtx.jface.text.source.IOverviewRuler#setAnnotationTypeLayer(java.lang.Object, int) | |
1003 */ | |
1004 public void setAnnotationTypeLayer(Object annotationType, int layer) { | |
1005 int j= fAnnotationsSortedByLayer.indexOf(annotationType); | |
1006 if (j !is -1) { | |
1007 fAnnotationsSortedByLayer.remove(j); | |
1008 fLayersSortedByLayer.remove(j); | |
1009 } | |
1010 | |
1011 if (layer >= 0) { | |
1012 int i= 0; | |
1013 int size= fLayersSortedByLayer.size(); | |
1014 while (i < size && layer >= ((Integer)fLayersSortedByLayer.get(i)).intValue()) | |
1015 i++; | |
1016 Integer layerObj= new Integer(layer); | |
1017 fLayersSortedByLayer.add(i, layerObj); | |
1018 fAnnotationsSortedByLayer.add(i, annotationType); | |
1019 } | |
1020 } | |
1021 | |
1022 /* | |
1023 * @see dwtx.jface.text.source.IOverviewRuler#setAnnotationTypeColor(java.lang.Object, dwt.graphics.Color) | |
1024 */ | |
1025 public void setAnnotationTypeColor(Object annotationType, Color color) { | |
1026 if (color !is null) | |
1027 fAnnotationTypes2Colors.put(annotationType, color); | |
1028 else | |
1029 fAnnotationTypes2Colors.remove(annotationType); | |
1030 } | |
1031 | |
1032 /** | |
1033 * Returns whether the given annotation type should be skipped by the drawing routine. | |
1034 * | |
1035 * @param annotationType the annotation type | |
1036 * @return <code>true</code> if annotation of the given type should be skipped | |
1037 */ | |
1038 private bool skip(Object annotationType) { | |
1039 return !contains(annotationType, fAllowedAnnotationTypes, fConfiguredAnnotationTypes); | |
1040 } | |
1041 | |
1042 /** | |
1043 * Returns whether the given annotation type should be skipped by the drawing routine of the header. | |
1044 * | |
1045 * @param annotationType the annotation type | |
1046 * @return <code>true</code> if annotation of the given type should be skipped | |
1047 * @since 3.0 | |
1048 */ | |
1049 private bool skipInHeader(Object annotationType) { | |
1050 return !contains(annotationType, fAllowedHeaderAnnotationTypes, fConfiguredHeaderAnnotationTypes); | |
1051 } | |
1052 | |
1053 /** | |
1054 * Returns whether the given annotation type is mapped to <code>true</code> | |
1055 * in the given <code>allowed</code> map or covered by the <code>configured</code> | |
1056 * set. | |
1057 * | |
1058 * @param annotationType the annotation type | |
1059 * @param allowed the map with allowed annotation types mapped to booleans | |
1060 * @param configured the set with configured annotation types | |
1061 * @return <code>true</code> if annotation is contained, <code>false</code> | |
1062 * otherwise | |
1063 * @since 3.0 | |
1064 */ | |
1065 private bool contains(Object annotationType, Map allowed, Set configured) { | |
1066 Boolean cached= (Boolean) allowed.get(annotationType); | |
1067 if (cached !is null) | |
1068 return cached.booleanValue(); | |
1069 | |
1070 bool covered= isCovered(annotationType, configured); | |
1071 allowed.put(annotationType, covered ? Boolean.TRUE : Boolean.FALSE); | |
1072 return covered; | |
1073 } | |
1074 | |
1075 /** | |
1076 * Computes whether the annotations of the given type are covered by the given <code>configured</code> | |
1077 * set. This is the case if either the type of the annotation or any of its | |
1078 * super types is contained in the <code>configured</code> set. | |
1079 * | |
1080 * @param annotationType the annotation type | |
1081 * @param configured the set with configured annotation types | |
1082 * @return <code>true</code> if annotation is covered, <code>false</code> | |
1083 * otherwise | |
1084 * @since 3.0 | |
1085 */ | |
1086 private bool isCovered(Object annotationType, Set configured) { | |
1087 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { | |
1088 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; | |
1089 Iterator e= configured.iterator(); | |
1090 while (e.hasNext()) { | |
1091 if (extension.isSubtype(annotationType,e.next())) | |
1092 return true; | |
1093 } | |
1094 return false; | |
1095 } | |
1096 return configured.contains(annotationType); | |
1097 } | |
1098 | |
1099 /** | |
1100 * Returns a specification of a color that lies between the given | |
1101 * foreground and background color using the given scale factor. | |
1102 * | |
1103 * @param fg the foreground color | |
1104 * @param bg the background color | |
1105 * @param scale the scale factor | |
1106 * @return the interpolated color | |
1107 */ | |
1108 private static RGB interpolate(RGB fg, RGB bg, double scale) { | |
1109 return new RGB( | |
1110 (int) ((1.0-scale) * fg.red + scale * bg.red), | |
1111 (int) ((1.0-scale) * fg.green + scale * bg.green), | |
1112 (int) ((1.0-scale) * fg.blue + scale * bg.blue) | |
1113 ); | |
1114 } | |
1115 | |
1116 /** | |
1117 * Returns the grey value in which the given color would be drawn in grey-scale. | |
1118 * | |
1119 * @param rgb the color | |
1120 * @return the grey-scale value | |
1121 */ | |
1122 private static double greyLevel(RGB rgb) { | |
1123 if (rgb.red is rgb.green && rgb.green is rgb.blue) | |
1124 return rgb.red; | |
1125 return (0.299 * rgb.red + 0.587 * rgb.green + 0.114 * rgb.blue + 0.5); | |
1126 } | |
1127 | |
1128 /** | |
1129 * Returns whether the given color is dark or light depending on the colors grey-scale level. | |
1130 * | |
1131 * @param rgb the color | |
1132 * @return <code>true</code> if the color is dark, <code>false</code> if it is light | |
1133 */ | |
1134 private static bool isDark(RGB rgb) { | |
1135 return greyLevel(rgb) > 128; | |
1136 } | |
1137 | |
1138 /** | |
1139 * Returns a color based on the color configured for the given annotation type and the given scale factor. | |
1140 * | |
1141 * @param annotationType the annotation type | |
1142 * @param scale the scale factor | |
1143 * @return the computed color | |
1144 */ | |
1145 private Color getColor(Object annotationType, double scale) { | |
1146 Color base= findColor(annotationType); | |
1147 if (base is null) | |
1148 return null; | |
1149 | |
1150 RGB baseRGB= base.getRGB(); | |
1151 RGB background= fCanvas.getBackground().getRGB(); | |
1152 | |
1153 bool darkBase= isDark(baseRGB); | |
1154 bool darkBackground= isDark(background); | |
1155 if (darkBase && darkBackground) | |
1156 background= new RGB(255, 255, 255); | |
1157 else if (!darkBase && !darkBackground) | |
1158 background= new RGB(0, 0, 0); | |
1159 | |
1160 return fSharedTextColors.getColor(interpolate(baseRGB, background, scale)); | |
1161 } | |
1162 | |
1163 /** | |
1164 * Returns the color for the given annotation type | |
1165 * | |
1166 * @param annotationType the annotation type | |
1167 * @return the color | |
1168 * @since 3.0 | |
1169 */ | |
1170 private Color findColor(Object annotationType) { | |
1171 Color color= (Color) fAnnotationTypes2Colors.get(annotationType); | |
1172 if (color !is null) | |
1173 return color; | |
1174 | |
1175 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { | |
1176 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; | |
1177 Object[] superTypes= extension.getSupertypes(annotationType); | |
1178 if (superTypes !is null) { | |
1179 for (int i= 0; i < superTypes.length; i++) { | |
1180 color= (Color) fAnnotationTypes2Colors.get(superTypes[i]); | |
1181 if (color !is null) | |
1182 return color; | |
1183 } | |
1184 } | |
1185 } | |
1186 | |
1187 return null; | |
1188 } | |
1189 | |
1190 /** | |
1191 * Returns the stroke color for the given annotation type and characteristics. | |
1192 * | |
1193 * @param annotationType the annotation type | |
1194 * @param temporary <code>true</code> if for temporary annotations | |
1195 * @return the stroke color | |
1196 */ | |
1197 private Color getStrokeColor(Object annotationType, bool temporary) { | |
1198 return getColor(annotationType, temporary && fIsTemporaryAnnotationDiscolored ? 0.5 : 0.2); | |
1199 } | |
1200 | |
1201 /** | |
1202 * Returns the fill color for the given annotation type and characteristics. | |
1203 * | |
1204 * @param annotationType the annotation type | |
1205 * @param temporary <code>true</code> if for temporary annotations | |
1206 * @return the fill color | |
1207 */ | |
1208 private Color getFillColor(Object annotationType, bool temporary) { | |
1209 return getColor(annotationType, temporary && fIsTemporaryAnnotationDiscolored ? 0.9 : 0.75); | |
1210 } | |
1211 | |
1212 /* | |
1213 * @see IVerticalRulerInfo#getLineOfLastMouseButtonActivity() | |
1214 */ | |
1215 public int getLineOfLastMouseButtonActivity() { | |
1216 if (fLastMouseButtonActivityLine >= fTextViewer.getDocument().getNumberOfLines()) | |
1217 fLastMouseButtonActivityLine= -1; | |
1218 return fLastMouseButtonActivityLine; | |
1219 } | |
1220 | |
1221 /* | |
1222 * @see IVerticalRulerInfo#toDocumentLineNumber(int) | |
1223 */ | |
1224 public int toDocumentLineNumber(int y_coordinate) { | |
1225 | |
1226 if (fTextViewer is null || y_coordinate is -1) | |
1227 return -1; | |
1228 | |
1229 int[] lineNumbers= toLineNumbers(y_coordinate); | |
1230 int bestLine= findBestMatchingLineNumber(lineNumbers); | |
1231 if (bestLine is -1 && lineNumbers.length > 0) | |
1232 return lineNumbers[0]; | |
1233 return bestLine; | |
1234 } | |
1235 | |
1236 /* | |
1237 * @see dwtx.jface.text.source.IVerticalRuler#getModel() | |
1238 */ | |
1239 public IAnnotationModel getModel() { | |
1240 return fModel; | |
1241 } | |
1242 | |
1243 /* | |
1244 * @see dwtx.jface.text.source.IOverviewRuler#getAnnotationHeight() | |
1245 */ | |
1246 public int getAnnotationHeight() { | |
1247 return fAnnotationHeight; | |
1248 } | |
1249 | |
1250 /* | |
1251 * @see dwtx.jface.text.source.IOverviewRuler#hasAnnotation(int) | |
1252 */ | |
1253 public bool hasAnnotation(int y) { | |
1254 return findBestMatchingLineNumber(toLineNumbers(y)) !is -1; | |
1255 } | |
1256 | |
1257 /* | |
1258 * @see dwtx.jface.text.source.IOverviewRuler#getHeaderControl() | |
1259 */ | |
1260 public Control getHeaderControl() { | |
1261 return fHeader; | |
1262 } | |
1263 | |
1264 /* | |
1265 * @see dwtx.jface.text.source.IOverviewRuler#addHeaderAnnotationType(java.lang.Object) | |
1266 */ | |
1267 public void addHeaderAnnotationType(Object annotationType) { | |
1268 fConfiguredHeaderAnnotationTypes.add(annotationType); | |
1269 fAllowedHeaderAnnotationTypes.clear(); | |
1270 } | |
1271 | |
1272 /* | |
1273 * @see dwtx.jface.text.source.IOverviewRuler#removeHeaderAnnotationType(java.lang.Object) | |
1274 */ | |
1275 public void removeHeaderAnnotationType(Object annotationType) { | |
1276 fConfiguredHeaderAnnotationTypes.remove(annotationType); | |
1277 fAllowedHeaderAnnotationTypes.clear(); | |
1278 } | |
1279 | |
1280 /** | |
1281 * Updates the header of this ruler. | |
1282 */ | |
1283 private void updateHeader() { | |
1284 if (fHeader is null || fHeader.isDisposed()) | |
1285 return; | |
1286 | |
1287 fHeader.setToolTipText(null); | |
1288 | |
1289 Object colorType= null; | |
1290 outer: for (int i= fAnnotationsSortedByLayer.size() -1; i >= 0; i--) { | |
1291 Object annotationType= fAnnotationsSortedByLayer.get(i); | |
1292 if (skipInHeader(annotationType) || skip(annotationType)) | |
1293 continue; | |
1294 | |
1295 Iterator e= new FilterIterator(annotationType, FilterIterator.PERSISTENT | FilterIterator.TEMPORARY | FilterIterator.IGNORE_BAGS, fCachedAnnotations.iterator()); | |
1296 while (e.hasNext()) { | |
1297 if (e.next() !is null) { | |
1298 colorType= annotationType; | |
1299 break outer; | |
1300 } | |
1301 } | |
1302 } | |
1303 | |
1304 Color color= null; | |
1305 if (colorType !is null) | |
1306 color= findColor(colorType); | |
1307 | |
1308 if (color is null) { | |
1309 if (fHeaderPainter !is null) | |
1310 fHeaderPainter.setColor(null); | |
1311 } else { | |
1312 if (fHeaderPainter is null) { | |
1313 fHeaderPainter= new HeaderPainter(); | |
1314 fHeader.addPaintListener(fHeaderPainter); | |
1315 } | |
1316 fHeaderPainter.setColor(color); | |
1317 } | |
1318 | |
1319 fHeader.redraw(); | |
1320 | |
1321 } | |
1322 | |
1323 /** | |
1324 * Updates the header tool tip text of this ruler. | |
1325 */ | |
1326 private void updateHeaderToolTipText() { | |
1327 if (fHeader is null || fHeader.isDisposed()) | |
1328 return; | |
1329 | |
1330 if (fHeader.getToolTipText() !is null) | |
1331 return; | |
1332 | |
1333 String overview= ""; //$NON-NLS-1$ | |
1334 | |
1335 for (int i= fAnnotationsSortedByLayer.size() -1; i >= 0; i--) { | |
1336 | |
1337 Object annotationType= fAnnotationsSortedByLayer.get(i); | |
1338 | |
1339 if (skipInHeader(annotationType) || skip(annotationType)) | |
1340 continue; | |
1341 | |
1342 int count= 0; | |
1343 String annotationTypeLabel= null; | |
1344 | |
1345 Iterator e= new FilterIterator(annotationType, FilterIterator.PERSISTENT | FilterIterator.TEMPORARY | FilterIterator.IGNORE_BAGS, fCachedAnnotations.iterator()); | |
1346 while (e.hasNext()) { | |
1347 Annotation annotation= (Annotation)e.next(); | |
1348 if (annotation !is null) { | |
1349 if (annotationTypeLabel is null) | |
1350 annotationTypeLabel= ((IAnnotationAccessExtension)fAnnotationAccess).getTypeLabel(annotation); | |
1351 count++; | |
1352 } | |
1353 } | |
1354 | |
1355 if (annotationTypeLabel !is null) { | |
1356 if (overview.length() > 0) | |
1357 overview += "\n"; //$NON-NLS-1$ | |
1358 overview += JFaceTextMessages.getFormattedString("OverviewRulerHeader.toolTipTextEntry", new Object[] {annotationTypeLabel, new Integer(count)}); //$NON-NLS-1$ | |
1359 } | |
1360 } | |
1361 | |
1362 if (overview.length() > 0) | |
1363 fHeader.setToolTipText(overview); | |
1364 } | |
1365 } |