Mercurial > projects > dwt-addons
annotate dwtx/jface/text/source/AnnotationRulerColumn.d @ 135:65801ad2b265
Regex fix for anon classes
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 24 Aug 2008 01:52:31 +0200 |
parents | 51e6e63f930e |
children | b6bad70d540a |
rev | line source |
---|---|
129 | 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 * Nikolay Botev <bono8106@hotmail.com> - [projection] Editor loses keyboard focus when expanding folded region - https://bugs.eclipse.org/bugs/show_bug.cgi?id=184255 | |
11 * Port to the D programming language: | |
12 * Frank Benoit <benoit@tionex.de> | |
13 *******************************************************************************/ | |
14 module dwtx.jface.text.source.AnnotationRulerColumn; | |
15 | |
131 | 16 import dwtx.jface.text.source.ISharedTextColors; // packageimport |
17 import dwtx.jface.text.source.ILineRange; // packageimport | |
18 import dwtx.jface.text.source.IAnnotationPresentation; // packageimport | |
19 import dwtx.jface.text.source.IVerticalRulerInfoExtension; // packageimport | |
20 import dwtx.jface.text.source.ICharacterPairMatcher; // packageimport | |
21 import dwtx.jface.text.source.TextInvocationContext; // packageimport | |
22 import dwtx.jface.text.source.LineChangeHover; // packageimport | |
23 import dwtx.jface.text.source.IChangeRulerColumn; // packageimport | |
24 import dwtx.jface.text.source.IAnnotationMap; // packageimport | |
25 import dwtx.jface.text.source.IAnnotationModelListenerExtension; // packageimport | |
26 import dwtx.jface.text.source.ISourceViewerExtension2; // packageimport | |
27 import dwtx.jface.text.source.IAnnotationHover; // packageimport | |
28 import dwtx.jface.text.source.ContentAssistantFacade; // packageimport | |
29 import dwtx.jface.text.source.IAnnotationAccess; // packageimport | |
30 import dwtx.jface.text.source.IVerticalRulerExtension; // packageimport | |
31 import dwtx.jface.text.source.IVerticalRulerColumn; // packageimport | |
32 import dwtx.jface.text.source.LineNumberRulerColumn; // packageimport | |
33 import dwtx.jface.text.source.MatchingCharacterPainter; // packageimport | |
34 import dwtx.jface.text.source.IAnnotationModelExtension; // packageimport | |
35 import dwtx.jface.text.source.ILineDifferExtension; // packageimport | |
36 import dwtx.jface.text.source.DefaultCharacterPairMatcher; // packageimport | |
37 import dwtx.jface.text.source.LineNumberChangeRulerColumn; // packageimport | |
38 import dwtx.jface.text.source.IAnnotationAccessExtension; // packageimport | |
39 import dwtx.jface.text.source.ISourceViewer; // packageimport | |
40 import dwtx.jface.text.source.AnnotationModel; // packageimport | |
41 import dwtx.jface.text.source.ILineDifferExtension2; // packageimport | |
42 import dwtx.jface.text.source.IAnnotationModelListener; // packageimport | |
43 import dwtx.jface.text.source.IVerticalRuler; // packageimport | |
44 import dwtx.jface.text.source.DefaultAnnotationHover; // packageimport | |
45 import dwtx.jface.text.source.SourceViewer; // packageimport | |
46 import dwtx.jface.text.source.SourceViewerConfiguration; // packageimport | |
47 import dwtx.jface.text.source.AnnotationBarHoverManager; // packageimport | |
48 import dwtx.jface.text.source.CompositeRuler; // packageimport | |
49 import dwtx.jface.text.source.ImageUtilities; // packageimport | |
50 import dwtx.jface.text.source.VisualAnnotationModel; // packageimport | |
51 import dwtx.jface.text.source.IAnnotationModel; // packageimport | |
52 import dwtx.jface.text.source.ISourceViewerExtension3; // packageimport | |
53 import dwtx.jface.text.source.ILineDiffInfo; // packageimport | |
54 import dwtx.jface.text.source.VerticalRulerEvent; // packageimport | |
55 import dwtx.jface.text.source.ChangeRulerColumn; // packageimport | |
56 import dwtx.jface.text.source.ILineDiffer; // packageimport | |
57 import dwtx.jface.text.source.AnnotationModelEvent; // packageimport | |
58 import dwtx.jface.text.source.AnnotationColumn; // packageimport | |
59 import dwtx.jface.text.source.IAnnotationHoverExtension; // packageimport | |
60 import dwtx.jface.text.source.AbstractRulerColumn; // packageimport | |
61 import dwtx.jface.text.source.ISourceViewerExtension; // packageimport | |
62 import dwtx.jface.text.source.AnnotationMap; // packageimport | |
63 import dwtx.jface.text.source.IVerticalRulerInfo; // packageimport | |
64 import dwtx.jface.text.source.IAnnotationModelExtension2; // packageimport | |
65 import dwtx.jface.text.source.LineRange; // packageimport | |
66 import dwtx.jface.text.source.IAnnotationAccessExtension2; // packageimport | |
67 import dwtx.jface.text.source.VerticalRuler; // packageimport | |
68 import dwtx.jface.text.source.JFaceTextMessages; // packageimport | |
69 import dwtx.jface.text.source.IOverviewRuler; // packageimport | |
70 import dwtx.jface.text.source.Annotation; // packageimport | |
71 import dwtx.jface.text.source.IVerticalRulerListener; // packageimport | |
72 import dwtx.jface.text.source.ISourceViewerExtension4; // packageimport | |
73 import dwtx.jface.text.source.AnnotationPainter; // packageimport | |
74 import dwtx.jface.text.source.IAnnotationHoverExtension2; // packageimport | |
75 import dwtx.jface.text.source.OverviewRuler; // packageimport | |
76 import dwtx.jface.text.source.OverviewRulerHoverManager; // packageimport | |
77 | |
78 | |
129 | 79 import dwt.dwthelper.utils; |
80 | |
81 import java.util.ArrayList; | |
82 import java.util.Collections; | |
83 import java.util.Comparator; | |
84 import java.util.HashMap; | |
85 import java.util.HashSet; | |
86 import java.util.Iterator; | |
87 import java.util.List; | |
88 import java.util.Map; | |
89 import java.util.Set; | |
90 | |
91 import dwt.DWT; | |
92 import dwt.custom.StyledText; | |
93 import dwt.events.DisposeEvent; | |
94 import dwt.events.DisposeListener; | |
95 import dwt.events.MouseEvent; | |
96 import dwt.events.MouseListener; | |
97 import dwt.events.MouseMoveListener; | |
98 import dwt.events.PaintEvent; | |
99 import dwt.events.PaintListener; | |
100 import dwt.graphics.Cursor; | |
101 import dwt.graphics.Font; | |
102 import dwt.graphics.GC; | |
103 import dwt.graphics.Image; | |
104 import dwt.graphics.Point; | |
105 import dwt.graphics.Rectangle; | |
106 import dwt.widgets.Canvas; | |
107 import dwt.widgets.Composite; | |
108 import dwt.widgets.Control; | |
109 import dwt.widgets.Display; | |
110 import dwtx.jface.text.BadLocationException; | |
111 import dwtx.jface.text.IDocument; | |
112 import dwtx.jface.text.IRegion; | |
113 import dwtx.jface.text.ITextListener; | |
114 import dwtx.jface.text.ITextViewer; | |
115 import dwtx.jface.text.ITextViewerExtension5; | |
116 import dwtx.jface.text.IViewportListener; | |
117 import dwtx.jface.text.JFaceTextUtil; | |
118 import dwtx.jface.text.Position; | |
119 import dwtx.jface.text.TextEvent; | |
120 | |
121 | |
122 /** | |
123 * A vertical ruler column showing graphical representations of annotations. | |
124 * Will become final. | |
125 * <p> | |
126 * Do not subclass. | |
127 * </p> | |
128 * | |
129 * @since 2.0 | |
130 */ | |
131 public class AnnotationRulerColumn : IVerticalRulerColumn, IVerticalRulerInfo, IVerticalRulerInfoExtension { | |
132 | |
133 /** | |
134 * Internal listener class. | |
135 */ | |
136 class InternalListener : IViewportListener, IAnnotationModelListener, ITextListener { | |
137 | |
138 /* | |
139 * @see IViewportListener#viewportChanged(int) | |
140 */ | |
141 public void viewportChanged(int verticalPosition) { | |
142 if (verticalPosition !is fScrollPos) | |
143 redraw(); | |
144 } | |
145 | |
146 /* | |
147 * @see IAnnotationModelListener#modelChanged(IAnnotationModel) | |
148 */ | |
149 public void modelChanged(IAnnotationModel model) { | |
150 postRedraw(); | |
151 } | |
152 | |
153 /* | |
154 * @see ITextListener#textChanged(TextEvent) | |
155 */ | |
156 public void textChanged(TextEvent e) { | |
157 if (e.getViewerRedrawState()) | |
158 postRedraw(); | |
159 } | |
160 } | |
161 | |
162 /** | |
163 * Implementation of <code>IRegion</code> that can be reused | |
164 * by setting the offset and the length. | |
165 */ | |
166 private static class ReusableRegion : Position , IRegion {} | |
167 | |
168 /** | |
169 * Pair of an annotation and their associated position. Used inside the paint method | |
170 * for sorting annotations based on the offset of their position. | |
171 * @since 3.0 | |
172 */ | |
173 private static class Tuple { | |
174 Annotation annotation; | |
175 Position position; | |
176 | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
177 this(Annotation annotation, Position position) { |
129 | 178 this.annotation= annotation; |
179 this.position= position; | |
180 } | |
181 } | |
182 | |
183 /** | |
184 * Comparator for <code>Tuple</code>s. | |
185 * @since 3.0 | |
186 */ | |
187 private static class TupleComparator : Comparator { | |
188 /* | |
189 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) | |
190 */ | |
191 public int compare(Object o1, Object o2) { | |
134 | 192 Position p1= (cast(Tuple) o1).position; |
193 Position p2= (cast(Tuple) o2).position; | |
129 | 194 return p1.getOffset() - p2.getOffset(); |
195 } | |
196 } | |
197 | |
198 /** This column's parent ruler */ | |
199 private CompositeRuler fParentRuler; | |
200 /** The cached text viewer */ | |
201 private ITextViewer fCachedTextViewer; | |
202 /** The cached text widget */ | |
203 private StyledText fCachedTextWidget; | |
204 /** The ruler's canvas */ | |
205 private Canvas fCanvas; | |
206 /** The vertical ruler's model */ | |
207 private IAnnotationModel fModel; | |
208 /** Cache for the actual scroll position in pixels */ | |
209 private int fScrollPos; | |
210 /** The buffer for double buffering */ | |
211 private Image fBuffer; | |
212 /** The internal listener */ | |
213 private InternalListener fInternalListener= new InternalListener(); | |
214 /** The width of this vertical ruler */ | |
215 private int fWidth; | |
216 /** Switch for enabling/disabling the setModel method. */ | |
217 private bool fAllowSetModel= true; | |
218 /** | |
219 * The list of annotation types to be shown in this ruler. | |
220 * @since 3.0 | |
221 */ | |
222 private Set fConfiguredAnnotationTypes= new HashSet(); | |
223 /** | |
224 * The list of allowed annotation types to be shown in this ruler. | |
225 * An allowed annotation type maps to <code>true</code>, a disallowed | |
226 * to <code>false</code>. | |
227 * @since 3.0 | |
228 */ | |
229 private Map fAllowedAnnotationTypes= new HashMap(); | |
230 /** | |
231 * The annotation access extension. | |
232 * @since 3.0 | |
233 */ | |
234 private IAnnotationAccessExtension fAnnotationAccessExtension; | |
235 /** | |
236 * The hover for this column. | |
237 * @since 3.0 | |
238 */ | |
239 private IAnnotationHover fHover; | |
240 /** | |
241 * The cached annotations. | |
242 * @since 3.0 | |
243 */ | |
244 private List fCachedAnnotations= new ArrayList(); | |
245 /** | |
246 * The comparator for sorting annotations according to the offset of their position. | |
247 * @since 3.0 | |
248 */ | |
249 private Comparator fTupleComparator= new TupleComparator(); | |
250 /** | |
251 * The hit detection cursor. | |
252 * @since 3.0 | |
253 */ | |
254 private Cursor fHitDetectionCursor; | |
255 /** | |
256 * The last cursor. | |
257 * @since 3.0 | |
258 */ | |
259 private Cursor fLastCursor; | |
260 /** | |
261 * This ruler's mouse listener. | |
262 * @since 3.0 | |
263 */ | |
264 private MouseListener fMouseListener; | |
265 | |
266 /** | |
267 * Constructs this column with the given arguments. | |
268 * | |
269 * @param model the annotation model to get the annotations from | |
270 * @param width the width of the vertical ruler | |
271 * @param annotationAccess the annotation access | |
272 * @since 3.0 | |
273 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
274 public this(IAnnotationModel model, int width, IAnnotationAccess annotationAccess) { |
129 | 275 this(width, annotationAccess); |
276 fAllowSetModel= false; | |
277 fModel= model; | |
278 fModel.addAnnotationModelListener(fInternalListener); | |
279 } | |
280 | |
281 /** | |
282 * Constructs this column with the given arguments. | |
283 * | |
284 * @param width the width of the vertical ruler | |
285 * @param annotationAccess the annotation access | |
286 * @since 3.0 | |
287 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
288 public this(int width, IAnnotationAccess annotationAccess) { |
129 | 289 fWidth= width; |
290 if (annotationAccess instanceof IAnnotationAccessExtension) | |
134 | 291 fAnnotationAccessExtension= cast(IAnnotationAccessExtension) annotationAccess; |
129 | 292 } |
293 | |
294 /** | |
295 * Constructs this column with the given arguments. | |
296 * | |
297 * @param model the annotation model to get the annotations from | |
298 * @param width the width of the vertical ruler | |
299 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
300 public this(IAnnotationModel model, int width) { |
129 | 301 fWidth= width; |
302 fAllowSetModel= false; | |
303 fModel= model; | |
304 fModel.addAnnotationModelListener(fInternalListener); | |
305 } | |
306 | |
307 /** | |
308 * Constructs this column with the given width. | |
309 * | |
310 * @param width the width of the vertical ruler | |
311 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
312 public this(int width) { |
129 | 313 fWidth= width; |
314 } | |
315 | |
316 /* | |
317 * @see IVerticalRulerColumn#getControl() | |
318 */ | |
319 public Control getControl() { | |
320 return fCanvas; | |
321 } | |
322 | |
323 /* | |
324 * @see IVerticalRulerColumn#getWidth() | |
325 */ | |
326 public int getWidth() { | |
327 return fWidth; | |
328 } | |
329 | |
330 /* | |
331 * @see IVerticalRulerColumn#createControl(CompositeRuler, Composite) | |
332 */ | |
333 public Control createControl(CompositeRuler parentRuler, Composite parentControl) { | |
334 | |
335 fParentRuler= parentRuler; | |
336 fCachedTextViewer= parentRuler.getTextViewer(); | |
337 fCachedTextWidget= fCachedTextViewer.getTextWidget(); | |
338 | |
339 fHitDetectionCursor= new Cursor(parentControl.getDisplay(), DWT.CURSOR_HAND); | |
340 | |
341 fCanvas= createCanvas(parentControl); | |
342 | |
135 | 343 fCanvas.addPaintListener(new class() PaintListener { |
129 | 344 public void paintControl(PaintEvent event) { |
345 if (fCachedTextViewer !is null) | |
346 doubleBufferPaint(event.gc); | |
347 } | |
348 }); | |
349 | |
135 | 350 fCanvas.addDisposeListener(new class() DisposeListener { |
129 | 351 public void widgetDisposed(DisposeEvent e) { |
352 handleDispose(); | |
353 fCachedTextViewer= null; | |
354 fCachedTextWidget= null; | |
355 } | |
356 }); | |
357 | |
135 | 358 fMouseListener= new class() MouseListener { |
129 | 359 public void mouseUp(MouseEvent event) { |
360 int lineNumber; | |
361 if (isPropagatingMouseListener()) { | |
362 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y); | |
363 lineNumber= fParentRuler.getLineOfLastMouseButtonActivity(); | |
364 } else | |
365 lineNumber= fParentRuler.toDocumentLineNumber(event.y); | |
366 | |
367 if (1 is event.button) | |
368 mouseClicked(lineNumber); | |
369 } | |
370 | |
371 public void mouseDown(MouseEvent event) { | |
372 if (isPropagatingMouseListener()) | |
373 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y); | |
374 } | |
375 | |
376 public void mouseDoubleClick(MouseEvent event) { | |
377 int lineNumber; | |
378 if (isPropagatingMouseListener()) { | |
379 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y); | |
380 lineNumber= fParentRuler.getLineOfLastMouseButtonActivity(); | |
381 } else | |
382 lineNumber= fParentRuler.toDocumentLineNumber(event.y); | |
383 | |
384 if (1 is event.button) | |
385 mouseDoubleClicked(lineNumber); | |
386 } | |
387 }; | |
388 fCanvas.addMouseListener(fMouseListener); | |
389 | |
135 | 390 fCanvas.addMouseMoveListener(new class() MouseMoveListener { |
129 | 391 /* |
392 * @see dwt.events.MouseMoveListener#mouseMove(dwt.events.MouseEvent) | |
393 * @since 3.0 | |
394 */ | |
395 public void mouseMove(MouseEvent e) { | |
396 handleMouseMove(e); | |
397 } | |
398 }); | |
399 | |
400 if (fCachedTextViewer !is null) { | |
401 fCachedTextViewer.addViewportListener(fInternalListener); | |
402 fCachedTextViewer.addTextListener(fInternalListener); | |
403 } | |
404 | |
405 return fCanvas; | |
406 } | |
407 | |
408 /** | |
409 * Creates a canvas with the given parent. | |
410 * | |
411 * @param parent the parent | |
412 * @return the created canvas | |
413 */ | |
414 private Canvas createCanvas(Composite parent) { | |
135 | 415 return new class(parent, DWT.NO_BACKGROUND | DWT.NO_FOCUS) Canvas { |
129 | 416 /* |
417 * @see dwt.widgets.Control#addMouseListener(dwt.events.MouseListener) | |
418 * @since 3.0 | |
419 */ | |
420 public void addMouseListener(MouseListener listener) { | |
421 if (isPropagatingMouseListener() || listener is fMouseListener) | |
422 super.addMouseListener(listener); | |
423 } | |
424 }; | |
425 } | |
426 | |
427 /** | |
428 * Tells whether this ruler column propagates mouse listener | |
429 * events to its parent. | |
430 * | |
431 * @return <code>true</code> if propagating to parent | |
432 * @since 3.0 | |
433 */ | |
434 protected bool isPropagatingMouseListener() { | |
435 return true; | |
436 } | |
437 | |
438 /** | |
439 * Hook method for a mouse double click event on the given ruler line. | |
440 * | |
441 * @param rulerLine the ruler line | |
442 */ | |
443 protected void mouseDoubleClicked(int rulerLine) { | |
444 } | |
445 | |
446 /** | |
447 * Hook method for a mouse click event on the given ruler line. | |
448 * | |
449 * @param rulerLine the ruler line | |
450 * @since 3.0 | |
451 */ | |
452 protected void mouseClicked(int rulerLine) { | |
453 } | |
454 | |
455 /** | |
456 * Handles mouse moves. | |
457 * | |
458 * @param event the mouse move event | |
459 */ | |
460 private void handleMouseMove(MouseEvent event) { | |
461 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y); | |
462 if (fCachedTextViewer !is null) { | |
463 int line= toDocumentLineNumber(event.y); | |
464 Cursor cursor= (hasAnnotation(line) ? fHitDetectionCursor : null); | |
465 if (cursor !is fLastCursor) { | |
466 fCanvas.setCursor(cursor); | |
467 fLastCursor= cursor; | |
468 } | |
469 } | |
470 } | |
471 | |
472 /** | |
473 * Tells whether the given line contains an annotation. | |
474 * | |
475 * @param lineNumber the line number | |
476 * @return <code>true</code> if the given line contains an annotation | |
477 */ | |
478 protected bool hasAnnotation(int lineNumber) { | |
479 | |
480 IAnnotationModel model= fModel; | |
481 if (fModel instanceof IAnnotationModelExtension) | |
134 | 482 model= (cast(IAnnotationModelExtension)fModel).getAnnotationModel(SourceViewer.MODEL_ANNOTATION_MODEL); |
129 | 483 |
484 if (model is null) | |
485 return false; | |
486 | |
487 IRegion line; | |
488 try { | |
489 IDocument d= fCachedTextViewer.getDocument(); | |
490 if (d is null) | |
491 return false; | |
492 | |
493 line= d.getLineInformation(lineNumber); | |
494 } catch (BadLocationException ex) { | |
495 return false; | |
496 } | |
497 | |
498 int lineStart= line.getOffset(); | |
499 int lineLength= line.getLength(); | |
500 | |
501 Iterator e; | |
502 if (fModel instanceof IAnnotationModelExtension2) | |
134 | 503 e= (cast(IAnnotationModelExtension2)fModel).getAnnotationIterator(lineStart, lineLength + 1, true, true); |
129 | 504 else |
505 e= model.getAnnotationIterator(); | |
506 | |
507 while (e.hasNext()) { | |
134 | 508 Annotation a= cast(Annotation) e.next(); |
129 | 509 |
510 if (a.isMarkedDeleted()) | |
511 continue; | |
512 | |
513 if (skip(a)) | |
514 continue; | |
515 | |
516 Position p= model.getPosition(a); | |
517 if (p is null || p.isDeleted()) | |
518 continue; | |
519 | |
520 if (p.overlapsWith(lineStart, lineLength) || p.length is 0 && p.offset is lineStart + lineLength) | |
521 return true; | |
522 } | |
523 | |
524 return false; | |
525 } | |
526 | |
527 /** | |
528 * Disposes the ruler's resources. | |
529 */ | |
530 private void handleDispose() { | |
531 | |
532 if (fCachedTextViewer !is null) { | |
533 fCachedTextViewer.removeViewportListener(fInternalListener); | |
534 fCachedTextViewer.removeTextListener(fInternalListener); | |
535 } | |
536 | |
537 if (fModel !is null) | |
538 fModel.removeAnnotationModelListener(fInternalListener); | |
539 | |
540 if (fBuffer !is null) { | |
541 fBuffer.dispose(); | |
542 fBuffer= null; | |
543 } | |
544 | |
545 if (fHitDetectionCursor !is null) { | |
546 fHitDetectionCursor.dispose(); | |
547 fHitDetectionCursor= null; | |
548 } | |
549 | |
550 fConfiguredAnnotationTypes.clear(); | |
551 fAllowedAnnotationTypes.clear(); | |
552 fAnnotationAccessExtension= null; | |
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 gc.setFont(fCachedTextWidget.getFont()); | |
579 try { | |
580 gc.setBackground(fCanvas.getBackground()); | |
581 gc.fillRectangle(0, 0, size.x, size.y); | |
582 | |
583 if (fCachedTextViewer instanceof ITextViewerExtension5) | |
584 doPaint1(gc); | |
585 else | |
586 doPaint(gc); | |
587 } finally { | |
588 gc.dispose(); | |
589 } | |
590 | |
591 dest.drawImage(fBuffer, 0, 0); | |
592 } | |
593 | |
594 /** | |
595 * Returns the document offset of the upper left corner of the source viewer's | |
596 * view port, possibly including partially visible lines. | |
597 * | |
598 * @return document offset of the upper left corner including partially visible lines | |
599 */ | |
600 protected int getInclusiveTopIndexStartOffset() { | |
601 if (fCachedTextWidget is null || fCachedTextWidget.isDisposed()) | |
602 return -1; | |
603 | |
604 IDocument document= fCachedTextViewer.getDocument(); | |
605 if (document is null) | |
606 return -1; | |
607 | |
608 int top= JFaceTextUtil.getPartialTopIndex(fCachedTextViewer); | |
609 try { | |
610 return document.getLineOffset(top); | |
611 } catch (BadLocationException x) { | |
612 return -1; | |
613 } | |
614 } | |
615 | |
616 /** | |
617 * Returns the first invisible document offset of the lower right corner of the source viewer's view port, | |
618 * possibly including partially visible lines. | |
619 * | |
620 * @return the first invisible document offset of the lower right corner of the view port | |
621 */ | |
622 private int getExclusiveBottomIndexEndOffset() { | |
623 if (fCachedTextWidget is null || fCachedTextWidget.isDisposed()) | |
624 return -1; | |
625 | |
626 IDocument document= fCachedTextViewer.getDocument(); | |
627 if (document is null) | |
628 return -1; | |
629 | |
630 int bottom= JFaceTextUtil.getPartialBottomIndex(fCachedTextViewer); | |
631 try { | |
632 if (bottom >= document.getNumberOfLines()) | |
633 bottom= document.getNumberOfLines() - 1; | |
634 return document.getLineOffset(bottom) + document.getLineLength(bottom); | |
635 } catch (BadLocationException x) { | |
636 return -1; | |
637 } | |
638 } | |
639 | |
640 /** | |
641 * Draws the vertical ruler w/o drawing the Canvas background. | |
642 * | |
643 * @param gc the GC to draw into | |
644 */ | |
645 protected void doPaint(GC gc) { | |
646 | |
647 if (fModel is null || fCachedTextViewer is null) | |
648 return; | |
649 | |
650 int topLeft= getInclusiveTopIndexStartOffset(); | |
651 // http://dev.eclipse.org/bugs/show_bug.cgi?id=14938 | |
652 // http://dev.eclipse.org/bugs/show_bug.cgi?id=22487 | |
653 // we want the exclusive offset (right after the last character) | |
654 int bottomRight= getExclusiveBottomIndexEndOffset(); | |
655 int viewPort= bottomRight - topLeft; | |
656 | |
657 fScrollPos= fCachedTextWidget.getTopPixel(); | |
658 Point dimension= fCanvas.getSize(); | |
659 | |
660 IDocument doc= fCachedTextViewer.getDocument(); | |
661 if (doc is null) | |
662 return; | |
663 | |
664 int topLine= -1, bottomLine= -1; | |
665 try { | |
666 IRegion region= fCachedTextViewer.getVisibleRegion(); | |
667 topLine= doc.getLineOfOffset(region.getOffset()); | |
668 bottomLine= doc.getLineOfOffset(region.getOffset() + region.getLength()); | |
669 } catch (BadLocationException x) { | |
670 return; | |
671 } | |
672 | |
673 // draw Annotations | |
674 Rectangle r= new Rectangle(0, 0, 0, 0); | |
675 int maxLayer= 1; // loop at least once through layers. | |
676 | |
677 for (int layer= 0; layer < maxLayer; layer++) { | |
678 Iterator iter; | |
679 if (fModel instanceof IAnnotationModelExtension2) | |
134 | 680 iter= (cast(IAnnotationModelExtension2)fModel).getAnnotationIterator(topLeft, viewPort + 1, true, true); |
129 | 681 else |
682 iter= fModel.getAnnotationIterator(); | |
683 | |
684 while (iter.hasNext()) { | |
134 | 685 Annotation annotation= cast(Annotation) iter.next(); |
129 | 686 |
687 int lay= IAnnotationAccessExtension.DEFAULT_LAYER; | |
688 if (fAnnotationAccessExtension !is null) | |
689 lay= fAnnotationAccessExtension.getLayer(annotation); | |
690 maxLayer= Math.max(maxLayer, lay+1); // dynamically update layer maximum | |
691 if (lay !is layer) // wrong layer: skip annotation | |
692 continue; | |
693 | |
694 if (skip(annotation)) | |
695 continue; | |
696 | |
697 Position position= fModel.getPosition(annotation); | |
698 if (position is null) | |
699 continue; | |
700 | |
701 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=20284 | |
702 // Position.overlapsWith returns false if the position just starts at the end | |
703 // of the specified range. If the position has zero length, we want to include it anyhow | |
704 int viewPortSize= position.getLength() is 0 ? viewPort + 1 : viewPort; | |
705 if (!position.overlapsWith(topLeft, viewPortSize)) | |
706 continue; | |
707 | |
708 try { | |
709 | |
710 int offset= position.getOffset(); | |
711 int length= position.getLength(); | |
712 | |
713 int startLine= doc.getLineOfOffset(offset); | |
714 if (startLine < topLine) | |
715 startLine= topLine; | |
716 | |
717 int endLine= startLine; | |
718 if (length > 0) | |
719 endLine= doc.getLineOfOffset(offset + length - 1); | |
720 if (endLine > bottomLine) | |
721 endLine= bottomLine; | |
722 | |
723 startLine -= topLine; | |
724 endLine -= topLine; | |
725 | |
726 r.x= 0; | |
727 r.y= JFaceTextUtil.computeLineHeight(fCachedTextWidget, 0, startLine, startLine) - fScrollPos; | |
728 | |
729 r.width= dimension.x; | |
730 int lines= endLine - startLine; | |
731 | |
732 r.height= JFaceTextUtil.computeLineHeight(fCachedTextWidget, startLine, endLine + 1, lines + 1); | |
733 | |
734 if (r.y < dimension.y && fAnnotationAccessExtension !is null) // annotation within visible area | |
735 fAnnotationAccessExtension.paint(annotation, gc, fCanvas, r); | |
736 | |
737 } catch (BadLocationException x) { | |
738 } | |
739 } | |
740 } | |
741 } | |
742 | |
743 /** | |
744 * Draws the vertical ruler w/o drawing the Canvas background. Implementation based | |
745 * on <code>ITextViewerExtension5</code>. Will replace <code>doPaint(GC)</code>. | |
746 * | |
747 * @param gc the GC to draw into | |
748 */ | |
749 protected void doPaint1(GC gc) { | |
750 | |
751 if (fModel is null || fCachedTextViewer is null) | |
752 return; | |
753 | |
134 | 754 ITextViewerExtension5 extension= cast(ITextViewerExtension5) fCachedTextViewer; |
129 | 755 |
756 fScrollPos= fCachedTextWidget.getTopPixel(); | |
757 Point dimension= fCanvas.getSize(); | |
758 | |
759 int vOffset= getInclusiveTopIndexStartOffset(); | |
760 int vLength= getExclusiveBottomIndexEndOffset() - vOffset; | |
761 | |
762 // draw Annotations | |
763 Rectangle r= new Rectangle(0, 0, 0, 0); | |
764 ReusableRegion range= new ReusableRegion(); | |
765 | |
766 int minLayer= Integer.MAX_VALUE, maxLayer= Integer.MIN_VALUE; | |
767 fCachedAnnotations.clear(); | |
768 Iterator iter; | |
769 if (fModel instanceof IAnnotationModelExtension2) | |
134 | 770 iter= (cast(IAnnotationModelExtension2)fModel).getAnnotationIterator(vOffset, vLength + 1, true, true); |
129 | 771 else |
772 iter= fModel.getAnnotationIterator(); | |
773 | |
774 while (iter.hasNext()) { | |
134 | 775 Annotation annotation= cast(Annotation) iter.next(); |
129 | 776 |
777 if (skip(annotation)) | |
778 continue; | |
779 | |
780 Position position= fModel.getPosition(annotation); | |
781 if (position is null) | |
782 continue; | |
783 | |
784 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=217710 | |
785 int extendedVLength= position.getLength() is 0 ? vLength + 1 : vLength; | |
786 if (!position.overlapsWith(vOffset, extendedVLength)) | |
787 continue; | |
788 | |
789 int lay= IAnnotationAccessExtension.DEFAULT_LAYER; | |
790 if (fAnnotationAccessExtension !is null) | |
791 lay= fAnnotationAccessExtension.getLayer(annotation); | |
792 | |
793 minLayer= Math.min(minLayer, lay); | |
794 maxLayer= Math.max(maxLayer, lay); | |
795 fCachedAnnotations.add(new Tuple(annotation, position)); | |
796 } | |
797 Collections.sort(fCachedAnnotations, fTupleComparator); | |
798 | |
799 for (int layer= minLayer; layer <= maxLayer; layer++) { | |
800 for (int i= 0, n= fCachedAnnotations.size(); i < n; i++) { | |
134 | 801 Tuple tuple= cast(Tuple) fCachedAnnotations.get(i); |
129 | 802 Annotation annotation= tuple.annotation; |
803 Position position= tuple.position; | |
804 | |
805 int lay= IAnnotationAccessExtension.DEFAULT_LAYER; | |
806 if (fAnnotationAccessExtension !is null) | |
807 lay= fAnnotationAccessExtension.getLayer(annotation); | |
808 if (lay !is layer) // wrong layer: skip annotation | |
809 continue; | |
810 | |
811 range.setOffset(position.getOffset()); | |
812 range.setLength(position.getLength()); | |
813 IRegion widgetRegion= extension.modelRange2WidgetRange(range); | |
814 if (widgetRegion is null) | |
815 continue; | |
816 | |
817 int startLine= extension.widgetLineOfWidgetOffset(widgetRegion.getOffset()); | |
818 if (startLine is -1) | |
819 continue; | |
820 | |
821 int endLine= extension.widgetLineOfWidgetOffset(widgetRegion.getOffset() + Math.max(widgetRegion.getLength() -1, 0)); | |
822 if (endLine is -1) | |
823 continue; | |
824 | |
825 r.x= 0; | |
826 r.y= JFaceTextUtil.computeLineHeight(fCachedTextWidget, 0, startLine, startLine) - fScrollPos; | |
827 | |
828 r.width= dimension.x; | |
829 int lines= endLine - startLine; | |
830 r.height= JFaceTextUtil.computeLineHeight(fCachedTextWidget, startLine, endLine + 1, lines + 1); | |
831 | |
832 if (r.y < dimension.y && fAnnotationAccessExtension !is null) // annotation within visible area | |
833 fAnnotationAccessExtension.paint(annotation, gc, fCanvas, r); | |
834 } | |
835 } | |
836 | |
837 fCachedAnnotations.clear(); | |
838 } | |
839 | |
840 | |
841 /** | |
842 * Post a redraw request for this column into the UI thread. | |
843 */ | |
844 private void postRedraw() { | |
845 if (fCanvas !is null && !fCanvas.isDisposed()) { | |
846 Display d= fCanvas.getDisplay(); | |
847 if (d !is null) { | |
135 | 848 d.asyncExec(new class() Runnable { |
129 | 849 public void run() { |
850 redraw(); | |
851 } | |
852 }); | |
853 } | |
854 } | |
855 } | |
856 | |
857 /* | |
858 * @see IVerticalRulerColumn#redraw() | |
859 */ | |
860 public void redraw() { | |
861 if (fCanvas !is null && !fCanvas.isDisposed()) { | |
862 GC gc= new GC(fCanvas); | |
863 doubleBufferPaint(gc); | |
864 gc.dispose(); | |
865 } | |
866 } | |
867 | |
868 /* | |
869 * @see IVerticalRulerColumn#setModel | |
870 */ | |
871 public void setModel(IAnnotationModel model) { | |
872 if (fAllowSetModel && model !is fModel) { | |
873 | |
874 if (fModel !is null) | |
875 fModel.removeAnnotationModelListener(fInternalListener); | |
876 | |
877 fModel= model; | |
878 | |
879 if (fModel !is null) | |
880 fModel.addAnnotationModelListener(fInternalListener); | |
881 | |
882 postRedraw(); | |
883 } | |
884 } | |
885 | |
886 /* | |
887 * @see IVerticalRulerColumn#setFont(Font) | |
888 */ | |
889 public void setFont(Font font) { | |
890 } | |
891 | |
892 /** | |
893 * Returns the cached text viewer. | |
894 * | |
895 * @return the cached text viewer | |
896 */ | |
897 protected ITextViewer getCachedTextViewer() { | |
898 return fCachedTextViewer; | |
899 } | |
900 | |
901 /* | |
902 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#getModel() | |
903 */ | |
904 public IAnnotationModel getModel() { | |
905 return fModel; | |
906 } | |
907 | |
908 /** | |
909 * Adds the given annotation type to this annotation ruler column. Starting | |
910 * with this call, annotations of the given type are shown in this annotation | |
911 * ruler column. | |
912 * | |
913 * @param annotationType the annotation type | |
914 * @since 3.0 | |
915 */ | |
916 public void addAnnotationType(Object annotationType) { | |
917 fConfiguredAnnotationTypes.add(annotationType); | |
918 fAllowedAnnotationTypes.clear(); | |
919 } | |
920 | |
921 /* | |
922 * @see dwtx.jface.text.source.IVerticalRulerInfo#getLineOfLastMouseButtonActivity() | |
923 * @since 3.0 | |
924 */ | |
925 public int getLineOfLastMouseButtonActivity() { | |
926 return fParentRuler.getLineOfLastMouseButtonActivity(); | |
927 } | |
928 | |
929 /* | |
930 * @see dwtx.jface.text.source.IVerticalRulerInfo#toDocumentLineNumber(int) | |
931 * @since 3.0 | |
932 */ | |
933 public int toDocumentLineNumber(int y_coordinate) { | |
934 return fParentRuler.toDocumentLineNumber(y_coordinate); | |
935 } | |
936 | |
937 /** | |
938 * Removes the given annotation type from this annotation ruler column. | |
939 * Annotations of the given type are no longer shown in this annotation | |
940 * ruler column. | |
941 * | |
942 * @param annotationType the annotation type | |
943 * @since 3.0 | |
944 */ | |
945 public void removeAnnotationType(Object annotationType) { | |
946 fConfiguredAnnotationTypes.remove(annotationType); | |
947 fAllowedAnnotationTypes.clear(); | |
948 } | |
949 | |
950 /** | |
951 * Returns whether the given annotation should be skipped by the drawing | |
952 * routine. | |
953 * | |
954 * @param annotation the annotation | |
955 * @return <code>true</code> if annotation of the given type should be | |
956 * skipped, <code>false</code> otherwise | |
957 * @since 3.0 | |
958 */ | |
959 private bool skip(Annotation annotation) { | |
960 Object annotationType= annotation.getType(); | |
134 | 961 Boolean allowed= cast(Boolean) fAllowedAnnotationTypes.get(annotationType); |
129 | 962 if (allowed !is null) |
963 return !allowed.booleanValue(); | |
964 | |
965 bool skip= skip(annotationType); | |
966 fAllowedAnnotationTypes.put(annotationType, !skip ? Boolean.TRUE : Boolean.FALSE); | |
967 return skip; | |
968 } | |
969 | |
970 /** | |
971 * Computes whether the annotation of the given type should be skipped or | |
972 * not. | |
973 * | |
974 * @param annotationType the annotation type | |
975 * @return <code>true</code> if annotation should be skipped, <code>false</code> | |
976 * otherwise | |
977 * @since 3.0 | |
978 */ | |
979 private bool skip(Object annotationType) { | |
980 if (fAnnotationAccessExtension !is null) { | |
981 Iterator e= fConfiguredAnnotationTypes.iterator(); | |
982 while (e.hasNext()) { | |
983 if (fAnnotationAccessExtension.isSubtype(annotationType, e.next())) | |
984 return false; | |
985 } | |
986 return true; | |
987 } | |
988 return !fConfiguredAnnotationTypes.contains(annotationType); | |
989 } | |
990 | |
991 /* | |
992 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#getHover() | |
993 * @since 3.0 | |
994 */ | |
995 public IAnnotationHover getHover() { | |
996 return fHover; | |
997 } | |
998 | |
999 /** | |
1000 * @param hover The hover to set. | |
1001 * @since 3.0 | |
1002 */ | |
1003 public void setHover(IAnnotationHover hover) { | |
1004 fHover= hover; | |
1005 } | |
1006 | |
1007 /* | |
1008 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#addVerticalRulerListener(dwtx.jface.text.source.IVerticalRulerListener) | |
1009 * @since 3.0 | |
1010 */ | |
1011 public void addVerticalRulerListener(IVerticalRulerListener listener) { | |
1012 throw new UnsupportedOperationException(); | |
1013 } | |
1014 | |
1015 /* | |
1016 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#removeVerticalRulerListener(dwtx.jface.text.source.IVerticalRulerListener) | |
1017 * @since 3.0 | |
1018 */ | |
1019 public void removeVerticalRulerListener(IVerticalRulerListener listener) { | |
1020 throw new UnsupportedOperationException(); | |
1021 } | |
1022 } |