Mercurial > projects > dwt-addons
annotate dwtx/jface/text/source/AnnotationModel.d @ 158:25f1f92fa3df
...
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 26 Aug 2008 02:46:34 +0200 |
parents | 7f75eaa8103a |
children | 7926b636c282 |
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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.text.source.AnnotationModel; | |
14 | |
131 | 15 import dwtx.jface.text.source.ISharedTextColors; // packageimport |
16 import dwtx.jface.text.source.ILineRange; // packageimport | |
17 import dwtx.jface.text.source.IAnnotationPresentation; // packageimport | |
18 import dwtx.jface.text.source.IVerticalRulerInfoExtension; // packageimport | |
19 import dwtx.jface.text.source.ICharacterPairMatcher; // packageimport | |
20 import dwtx.jface.text.source.TextInvocationContext; // packageimport | |
21 import dwtx.jface.text.source.LineChangeHover; // packageimport | |
22 import dwtx.jface.text.source.IChangeRulerColumn; // packageimport | |
23 import dwtx.jface.text.source.IAnnotationMap; // packageimport | |
24 import dwtx.jface.text.source.IAnnotationModelListenerExtension; // packageimport | |
25 import dwtx.jface.text.source.ISourceViewerExtension2; // packageimport | |
26 import dwtx.jface.text.source.IAnnotationHover; // packageimport | |
27 import dwtx.jface.text.source.ContentAssistantFacade; // packageimport | |
28 import dwtx.jface.text.source.IAnnotationAccess; // packageimport | |
29 import dwtx.jface.text.source.IVerticalRulerExtension; // packageimport | |
30 import dwtx.jface.text.source.IVerticalRulerColumn; // packageimport | |
31 import dwtx.jface.text.source.LineNumberRulerColumn; // packageimport | |
32 import dwtx.jface.text.source.MatchingCharacterPainter; // packageimport | |
33 import dwtx.jface.text.source.IAnnotationModelExtension; // packageimport | |
34 import dwtx.jface.text.source.ILineDifferExtension; // packageimport | |
35 import dwtx.jface.text.source.DefaultCharacterPairMatcher; // packageimport | |
36 import dwtx.jface.text.source.LineNumberChangeRulerColumn; // packageimport | |
37 import dwtx.jface.text.source.IAnnotationAccessExtension; // packageimport | |
38 import dwtx.jface.text.source.ISourceViewer; // packageimport | |
39 import dwtx.jface.text.source.ILineDifferExtension2; // packageimport | |
40 import dwtx.jface.text.source.IAnnotationModelListener; // packageimport | |
41 import dwtx.jface.text.source.IVerticalRuler; // packageimport | |
42 import dwtx.jface.text.source.DefaultAnnotationHover; // packageimport | |
43 import dwtx.jface.text.source.SourceViewer; // packageimport | |
44 import dwtx.jface.text.source.SourceViewerConfiguration; // packageimport | |
45 import dwtx.jface.text.source.AnnotationBarHoverManager; // packageimport | |
46 import dwtx.jface.text.source.CompositeRuler; // packageimport | |
47 import dwtx.jface.text.source.ImageUtilities; // packageimport | |
48 import dwtx.jface.text.source.VisualAnnotationModel; // packageimport | |
49 import dwtx.jface.text.source.IAnnotationModel; // packageimport | |
50 import dwtx.jface.text.source.ISourceViewerExtension3; // packageimport | |
51 import dwtx.jface.text.source.ILineDiffInfo; // packageimport | |
52 import dwtx.jface.text.source.VerticalRulerEvent; // packageimport | |
53 import dwtx.jface.text.source.ChangeRulerColumn; // packageimport | |
54 import dwtx.jface.text.source.ILineDiffer; // packageimport | |
55 import dwtx.jface.text.source.AnnotationModelEvent; // packageimport | |
56 import dwtx.jface.text.source.AnnotationColumn; // packageimport | |
57 import dwtx.jface.text.source.AnnotationRulerColumn; // packageimport | |
58 import dwtx.jface.text.source.IAnnotationHoverExtension; // packageimport | |
59 import dwtx.jface.text.source.AbstractRulerColumn; // packageimport | |
60 import dwtx.jface.text.source.ISourceViewerExtension; // packageimport | |
61 import dwtx.jface.text.source.AnnotationMap; // packageimport | |
62 import dwtx.jface.text.source.IVerticalRulerInfo; // packageimport | |
63 import dwtx.jface.text.source.IAnnotationModelExtension2; // packageimport | |
64 import dwtx.jface.text.source.LineRange; // packageimport | |
65 import dwtx.jface.text.source.IAnnotationAccessExtension2; // packageimport | |
66 import dwtx.jface.text.source.VerticalRuler; // packageimport | |
67 import dwtx.jface.text.source.JFaceTextMessages; // packageimport | |
68 import dwtx.jface.text.source.IOverviewRuler; // packageimport | |
69 import dwtx.jface.text.source.Annotation; // packageimport | |
70 import dwtx.jface.text.source.IVerticalRulerListener; // packageimport | |
71 import dwtx.jface.text.source.ISourceViewerExtension4; // packageimport | |
72 import dwtx.jface.text.source.AnnotationPainter; // packageimport | |
73 import dwtx.jface.text.source.IAnnotationHoverExtension2; // packageimport | |
74 import dwtx.jface.text.source.OverviewRuler; // packageimport | |
75 import dwtx.jface.text.source.OverviewRulerHoverManager; // packageimport | |
76 | |
129 | 77 import dwt.dwthelper.utils; |
153
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
146
diff
changeset
|
78 import dwtx.dwtxhelper.Collection; |
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
146
diff
changeset
|
79 |
129 | 80 import dwtx.core.runtime.Assert; |
81 import dwtx.jface.text.AbstractDocument; | |
82 import dwtx.jface.text.BadLocationException; | |
83 import dwtx.jface.text.BadPositionCategoryException; | |
84 import dwtx.jface.text.DocumentEvent; | |
85 import dwtx.jface.text.IDocument; | |
86 import dwtx.jface.text.IDocumentListener; | |
87 import dwtx.jface.text.ISynchronizable; | |
88 import dwtx.jface.text.Position; | |
89 | |
90 | |
91 /** | |
92 * Standard implementation of {@link IAnnotationModel} and its extension | |
93 * interfaces. This class can directly be used by clients. Subclasses may adapt | |
94 * this annotation model to other existing annotation mechanisms. This class | |
95 * also implements {@link dwtx.jface.text.ISynchronizable}. All | |
96 * modifications of the model's internal annotation map are synchronized using | |
97 * the model's lock object. | |
98 */ | |
99 public class AnnotationModel : IAnnotationModel, IAnnotationModelExtension, IAnnotationModelExtension2, ISynchronizable { | |
100 | |
101 | |
102 /** | |
103 * Iterator that returns the annotations for a given region. | |
145 | 104 * |
129 | 105 * @since 3.4 |
106 * @see AnnotationModel.RegionIterator#RegionIterator(Iterator, IAnnotationModel, int, int, bool, bool) | |
107 */ | |
108 private static final class RegionIterator : Iterator { | |
145 | 109 |
146 | 110 private const Iterator fParentIterator; |
111 private const bool fCanEndAfter; | |
112 private const bool fCanStartBefore; | |
113 private const IAnnotationModel fModel; | |
129 | 114 private Object fNext; |
115 private Position fRegion; | |
145 | 116 |
129 | 117 /** |
118 * Iterator that returns all annotations from the parent iterator which | |
119 * have a position in the given model inside the given region. | |
120 * <p> | |
121 * See {@link IAnnotationModelExtension2} for a definition of inside. | |
122 * </p> | |
145 | 123 * |
129 | 124 * @param parentIterator iterator containing all annotations |
125 * @param model the model to use to retrieve positions from for each | |
126 * annotation | |
127 * @param offset start position of the region | |
128 * @param length length of the region | |
129 * @param canStartBefore include annotations starting before region | |
130 * @param canEndAfter include annotations ending after region | |
131 * @see IAnnotationModelExtension2 | |
132 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
133 public this(Iterator parentIterator, IAnnotationModel model, int offset, int length, bool canStartBefore, bool canEndAfter) { |
129 | 134 fParentIterator= parentIterator; |
135 fModel= model; | |
136 fRegion= new Position(offset, length); | |
137 fCanEndAfter= canEndAfter; | |
138 fCanStartBefore= canStartBefore; | |
139 fNext= findNext(); | |
140 } | |
145 | 141 |
129 | 142 /* |
143 * @see java.util.Iterator#hasNext() | |
144 */ | |
145 public bool hasNext() { | |
146 return fNext !is null; | |
147 } | |
145 | 148 |
129 | 149 /* |
150 * @see java.util.Iterator#next() | |
151 */ | |
152 public Object next() { | |
153 if (!hasNext()) | |
154 throw new NoSuchElementException(); | |
145 | 155 |
129 | 156 Object result= fNext; |
157 fNext= findNext(); | |
158 return result; | |
159 } | |
145 | 160 |
129 | 161 /* |
162 * @see java.util.Iterator#remove() | |
163 */ | |
164 public void remove() { | |
165 throw new UnsupportedOperationException(); | |
166 } | |
145 | 167 |
129 | 168 private Object findNext() { |
169 while (fParentIterator.hasNext()) { | |
134 | 170 Annotation next= cast(Annotation) fParentIterator.next(); |
129 | 171 Position position= fModel.getPosition(next); |
172 if (position !is null) { | |
173 int offset= position.getOffset(); | |
174 if (isWithinRegion(offset, position.getLength())) | |
175 return next; | |
176 } | |
177 } | |
178 return null; | |
179 } | |
180 | |
181 private bool isWithinRegion(int start, int length) { | |
182 if (fCanStartBefore && fCanEndAfter) | |
183 return fRegion.overlapsWith(start, length); | |
184 else if (fCanStartBefore) | |
185 return fRegion.includes(start + length - 1); | |
186 else if (fCanEndAfter) | |
187 return fRegion.includes(start); | |
188 else | |
189 return fRegion.includes(start) && fRegion.includes(start + length - 1); | |
190 } | |
191 } | |
145 | 192 |
129 | 193 /** |
194 * An iterator iteration over a Positions and mapping positions to | |
195 * annotations using a provided map if the provided map contains the element. | |
145 | 196 * |
129 | 197 * @since 3.4 |
198 */ | |
199 private static final class AnnotationsInterator : Iterator { | |
145 | 200 |
129 | 201 private Object fNext; |
146 | 202 private const Position[] fPositions; |
129 | 203 private int fIndex; |
146 | 204 private const Map fMap; |
145 | 205 |
129 | 206 /** |
207 * @param positions positions to iterate over | |
208 * @param map a map to map positions to annotations | |
209 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
210 public this(Position[] positions, Map map) { |
129 | 211 fPositions= positions; |
212 fIndex= 0; | |
213 fMap= map; | |
214 fNext= findNext(); | |
215 } | |
145 | 216 |
129 | 217 /* (non-Javadoc) |
218 * @see java.util.Iterator#hasNext() | |
219 */ | |
220 public bool hasNext() { | |
221 return fNext !is null; | |
222 } | |
145 | 223 |
129 | 224 /* (non-Javadoc) |
225 * @see java.util.Iterator#next() | |
226 */ | |
227 public Object next() { | |
228 Object result= fNext; | |
229 fNext= findNext(); | |
230 return result; | |
231 } | |
145 | 232 |
129 | 233 /* (non-Javadoc) |
234 * @see java.util.Iterator#remove() | |
235 */ | |
236 public void remove() { | |
237 throw new UnsupportedOperationException(); | |
238 } | |
145 | 239 |
129 | 240 private Object findNext() { |
241 while (fIndex < fPositions.length) { | |
242 Position position= fPositions[fIndex]; | |
243 fIndex++; | |
244 if (fMap.containsKey(position)) | |
245 return fMap.get(position); | |
246 } | |
145 | 247 |
129 | 248 return null; |
249 } | |
250 } | |
251 | |
252 /** | |
253 * A single iterator builds its behavior based on a sequence of iterators. | |
254 * | |
255 * @since 3.1 | |
256 */ | |
257 private static class MetaIterator : Iterator { | |
258 | |
259 /** The iterator over a list of iterators. */ | |
260 private Iterator fSuperIterator; | |
261 /** The current iterator. */ | |
262 private Iterator fCurrent; | |
263 /** The current element. */ | |
264 private Object fCurrentElement; | |
265 | |
266 | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
267 public this(Iterator iterator) { |
129 | 268 fSuperIterator= iterator; |
134 | 269 fCurrent= cast(Iterator) fSuperIterator.next(); // there is at least one. |
129 | 270 } |
271 | |
272 public void remove() { | |
273 throw new UnsupportedOperationException(); | |
274 } | |
275 | |
276 public bool hasNext() { | |
277 if (fCurrentElement !is null) | |
278 return true; | |
279 | |
280 if (fCurrent.hasNext()) { | |
281 fCurrentElement= fCurrent.next(); | |
282 return true; | |
283 } else if (fSuperIterator.hasNext()) { | |
134 | 284 fCurrent= cast(Iterator) fSuperIterator.next(); |
129 | 285 return hasNext(); |
286 } else | |
287 return false; | |
288 } | |
289 | |
290 public Object next() { | |
291 if (!hasNext()) | |
292 throw new NoSuchElementException(); | |
293 | |
294 Object element= fCurrentElement; | |
295 fCurrentElement= null; | |
296 return element; | |
297 } | |
298 } | |
299 | |
300 /** | |
301 * Internal annotation model listener for forwarding annotation model changes from the attached models to the | |
302 * registered listeners of the outer most annotation model. | |
303 * | |
304 * @since 3.0 | |
305 */ | |
306 private class InternalModelListener : IAnnotationModelListener, IAnnotationModelListenerExtension { | |
307 | |
308 /* | |
309 * @see dwtx.jface.text.source.IAnnotationModelListener#modelChanged(dwtx.jface.text.source.IAnnotationModel) | |
310 */ | |
311 public void modelChanged(IAnnotationModel model) { | |
137 | 312 this.outer.fireModelChanged(new AnnotationModelEvent(model, true)); |
129 | 313 } |
314 | |
315 /* | |
316 * @see dwtx.jface.text.source.IAnnotationModelListenerExtension#modelChanged(dwtx.jface.text.source.AnnotationModelEvent) | |
317 */ | |
318 public void modelChanged(AnnotationModelEvent event) { | |
137 | 319 this.outer.fireModelChanged(event); |
129 | 320 } |
321 } | |
322 | |
323 /** | |
324 * The list of managed annotations | |
325 * @deprecated since 3.0 use <code>getAnnotationMap</code> instead | |
326 */ | |
327 protected Map fAnnotations; | |
328 /** | |
329 * The map which maps {@link Position} to {@link Annotation}. | |
330 * @since 3.4 | |
331 **/ | |
332 private IdentityHashMap fPositions; | |
333 /** The list of annotation model listeners */ | |
334 protected ArrayList fAnnotationModelListeners; | |
335 /** The document connected with this model */ | |
336 protected IDocument fDocument; | |
337 /** The number of open connections to the same document */ | |
338 private int fOpenConnections= 0; | |
339 /** The document listener for tracking whether document positions might have been changed. */ | |
340 private IDocumentListener fDocumentListener; | |
341 /** The flag indicating whether the document positions might have been changed. */ | |
342 private bool fDocumentChanged= true; | |
343 /** | |
344 * The model's attachment. | |
345 * @since 3.0 | |
346 */ | |
347 private Map fAttachments= new HashMap(); | |
348 /** | |
349 * The annotation model listener on attached sub-models. | |
350 * @since 3.0 | |
351 */ | |
352 private IAnnotationModelListener fModelListener= new InternalModelListener(); | |
353 /** | |
354 * The current annotation model event. | |
355 * @since 3.0 | |
356 */ | |
357 private AnnotationModelEvent fModelEvent; | |
358 /** | |
359 * The modification stamp. | |
360 * @since 3.0 | |
361 */ | |
362 private Object fModificationStamp= new Object(); | |
363 | |
364 /** | |
365 * Creates a new annotation model. The annotation is empty, i.e. does not | |
366 * manage any annotations and is not connected to any document. | |
367 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
368 public this() { |
129 | 369 fAnnotations= new AnnotationMap(10); |
370 fPositions= new IdentityHashMap(10); | |
371 fAnnotationModelListeners= new ArrayList(2); | |
372 | |
135 | 373 fDocumentListener= new class() IDocumentListener { |
129 | 374 |
375 public void documentAboutToBeChanged(DocumentEvent event) { | |
376 } | |
377 | |
378 public void documentChanged(DocumentEvent event) { | |
379 fDocumentChanged= true; | |
380 } | |
381 }; | |
382 } | |
383 | |
384 /** | |
385 * Returns the annotation map internally used by this annotation model. | |
386 * | |
387 * @return the annotation map internally used by this annotation model | |
388 * @since 3.0 | |
389 */ | |
390 protected IAnnotationMap getAnnotationMap() { | |
134 | 391 return cast(IAnnotationMap) fAnnotations; |
129 | 392 } |
393 | |
394 /* | |
395 * @see dwtx.jface.text.ISynchronizable#getLockObject() | |
396 * @since 3.0 | |
397 */ | |
398 public Object getLockObject() { | |
399 return getAnnotationMap().getLockObject(); | |
400 } | |
401 | |
402 /* | |
403 * @see dwtx.jface.text.ISynchronizable#setLockObject(java.lang.Object) | |
404 * @since 3.0 | |
405 */ | |
406 public void setLockObject(Object lockObject) { | |
407 getAnnotationMap().setLockObject(lockObject); | |
408 } | |
409 | |
410 /** | |
411 * Returns the current annotation model event. This is the event that will be sent out | |
412 * when calling <code>fireModelChanged</code>. | |
413 * | |
414 * @return the current annotation model event | |
415 * @since 3.0 | |
416 */ | |
417 protected final AnnotationModelEvent getAnnotationModelEvent() { | |
418 synchronized (getLockObject()) { | |
419 if (fModelEvent is null) { | |
420 fModelEvent= createAnnotationModelEvent(); | |
421 fModelEvent.markWorldChange(false); | |
422 fModificationStamp= fModelEvent; | |
423 } | |
424 return fModelEvent; | |
425 } | |
426 } | |
427 | |
428 /* | |
429 * @see dwtx.jface.text.source.IAnnotationModel#addAnnotation(dwtx.jface.text.source.Annotation, dwtx.jface.text.Position) | |
430 */ | |
431 public void addAnnotation(Annotation annotation, Position position) { | |
432 try { | |
433 addAnnotation(annotation, position, true); | |
434 } catch (BadLocationException e) { | |
435 // ignore invalid position | |
436 } | |
437 } | |
438 | |
439 /* | |
440 * @see dwtx.jface.text.source.IAnnotationModelExtension#replaceAnnotations(dwtx.jface.text.source.Annotation[], java.util.Map) | |
441 * @since 3.0 | |
442 */ | |
443 public void replaceAnnotations(Annotation[] annotationsToRemove, Map annotationsToAdd) { | |
444 try { | |
445 replaceAnnotations(annotationsToRemove, annotationsToAdd, true); | |
446 } catch (BadLocationException x) { | |
447 } | |
448 } | |
449 | |
450 /** | |
451 * Replaces the given annotations in this model and if advised fires a | |
452 * model change event. | |
453 * | |
454 * @param annotationsToRemove the annotations to be removed | |
455 * @param annotationsToAdd the annotations to be added | |
456 * @param fireModelChanged <code>true</code> if a model change event | |
457 * should be fired, <code>false</code> otherwise | |
458 * @throws BadLocationException in case an annotation should be added at an | |
459 * invalid position | |
460 * @since 3.0 | |
461 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
462 protected void replaceAnnotations(Annotation[] annotationsToRemove, Map annotationsToAdd, bool fireModelChanged) { |
129 | 463 |
464 if (annotationsToRemove !is null) { | |
465 for (int i= 0, length= annotationsToRemove.length; i < length; i++) | |
466 removeAnnotation(annotationsToRemove[i], false); | |
467 } | |
468 | |
469 if (annotationsToAdd !is null) { | |
470 Iterator iter= annotationsToAdd.entrySet().iterator(); | |
471 while (iter.hasNext()) { | |
157
7f75eaa8103a
volatile and cast Map.Entry
Frank Benoit <benoit@tionex.de>
parents:
153
diff
changeset
|
472 Map.Entry mapEntry= cast(Map.Entry) iter.next(); |
134 | 473 Annotation annotation= cast(Annotation) mapEntry.getKey(); |
474 Position position= cast(Position) mapEntry.getValue(); | |
129 | 475 addAnnotation(annotation, position, false); |
476 } | |
477 } | |
478 | |
479 if (fireModelChanged) | |
480 fireModelChanged(); | |
481 } | |
482 | |
483 /** | |
484 * Adds the given annotation to this model. Associates the | |
485 * annotation with the given position. If requested, all annotation | |
486 * model listeners are informed about this model change. If the annotation | |
487 * is already managed by this model nothing happens. | |
488 * | |
489 * @param annotation the annotation to add | |
490 * @param position the associate position | |
491 * @param fireModelChanged indicates whether to notify all model listeners | |
492 * @throws BadLocationException if the position is not a valid document position | |
493 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
494 protected void addAnnotation(Annotation annotation, Position position, bool fireModelChanged) { |
129 | 495 if (!fAnnotations.containsKey(annotation)) { |
496 | |
497 addPosition(fDocument, position); | |
498 fAnnotations.put(annotation, position); | |
499 fPositions.put(position, annotation); | |
500 synchronized (getLockObject()) { | |
501 getAnnotationModelEvent().annotationAdded(annotation); | |
502 } | |
503 | |
504 if (fireModelChanged) | |
505 fireModelChanged(); | |
506 } | |
507 } | |
508 | |
509 /* | |
510 * @see dwtx.jface.text.source.IAnnotationModel#addAnnotationModelListener(dwtx.jface.text.source.IAnnotationModelListener) | |
511 */ | |
512 public void addAnnotationModelListener(IAnnotationModelListener listener) { | |
513 if (!fAnnotationModelListeners.contains(listener)) { | |
514 fAnnotationModelListeners.add(listener); | |
138 | 515 if ( cast(IAnnotationModelListenerExtension)listener ) { |
134 | 516 IAnnotationModelListenerExtension extension= cast(IAnnotationModelListenerExtension) listener; |
129 | 517 AnnotationModelEvent event= createAnnotationModelEvent(); |
518 event.markSealed(); | |
519 extension.modelChanged(event); | |
520 } else | |
521 listener.modelChanged(this); | |
522 } | |
523 } | |
524 | |
525 /** | |
526 * Adds the given position to the default position category of the | |
527 * given document. | |
528 * | |
529 * @param document the document to which to add the position | |
530 * @param position the position to add | |
531 * @throws BadLocationException if the position is not a valid document position | |
532 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
533 protected void addPosition(IDocument document, Position position) { |
129 | 534 if (document !is null) |
535 document.addPosition(position); | |
536 } | |
537 | |
538 /** | |
539 * Removes the given position from the default position category of the | |
540 * given document. | |
541 * | |
542 * @param document the document to which to add the position | |
543 * @param position the position to add | |
544 * | |
545 * @since 3.0 | |
546 */ | |
547 protected void removePosition(IDocument document, Position position) { | |
548 if (document !is null) | |
549 document.removePosition(position); | |
550 } | |
551 | |
552 /* | |
553 * @see dwtx.jface.text.source.IAnnotationModel#connect(dwtx.jface.text.IDocument) | |
554 */ | |
555 public void connect(IDocument document) { | |
556 Assert.isTrue(fDocument is null || fDocument is document); | |
557 | |
558 if (fDocument is null) { | |
559 fDocument= document; | |
560 Iterator e= getAnnotationMap().valuesIterator(); | |
561 while (e.hasNext()) | |
562 try { | |
134 | 563 addPosition(fDocument, cast(Position) e.next()); |
129 | 564 } catch (BadLocationException x) { |
565 // ignore invalid position | |
566 } | |
567 } | |
568 | |
569 ++ fOpenConnections; | |
570 if (fOpenConnections is 1) { | |
571 fDocument.addDocumentListener(fDocumentListener); | |
572 connected(); | |
573 } | |
574 | |
575 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { | |
134 | 576 IAnnotationModel model= cast(IAnnotationModel) fAttachments.get(it.next()); |
129 | 577 model.connect(document); |
578 } | |
579 } | |
580 | |
581 /** | |
582 * Hook method. Is called as soon as this model becomes connected to a document. | |
583 * Subclasses may re-implement. | |
584 */ | |
585 protected void connected() { | |
586 } | |
587 | |
588 /** | |
589 * Hook method. Is called as soon as this model becomes disconnected from its document. | |
590 * Subclasses may re-implement. | |
591 */ | |
592 protected void disconnected() { | |
593 } | |
594 | |
595 /* | |
596 * @see dwtx.jface.text.source.IAnnotationModel#disconnect(dwtx.jface.text.IDocument) | |
597 */ | |
598 public void disconnect(IDocument document) { | |
599 | |
600 Assert.isTrue(fDocument is document); | |
601 | |
602 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { | |
134 | 603 IAnnotationModel model= cast(IAnnotationModel) fAttachments.get(it.next()); |
129 | 604 model.disconnect(document); |
605 } | |
606 | |
607 -- fOpenConnections; | |
608 if (fOpenConnections is 0) { | |
609 | |
610 disconnected(); | |
611 fDocument.removeDocumentListener(fDocumentListener); | |
612 | |
613 if (fDocument !is null) { | |
614 Iterator e= getAnnotationMap().valuesIterator(); | |
615 while (e.hasNext()) { | |
134 | 616 Position p= cast(Position) e.next(); |
129 | 617 removePosition(fDocument, p); |
618 } | |
619 fDocument= null; | |
620 } | |
621 } | |
622 } | |
623 | |
624 /** | |
625 * Informs all annotation model listeners that this model has been changed. | |
626 */ | |
627 protected void fireModelChanged() { | |
628 AnnotationModelEvent modelEvent= null; | |
629 | |
630 synchronized(getLockObject()) { | |
631 if (fModelEvent !is null) { | |
632 modelEvent= fModelEvent; | |
633 fModelEvent= null; | |
634 } | |
635 } | |
636 | |
637 if (modelEvent !is null) | |
638 fireModelChanged(modelEvent); | |
639 } | |
640 | |
641 /** | |
642 * Creates and returns a new annotation model event. Subclasses may override. | |
643 * | |
644 * @return a new and empty annotation model event | |
645 * @since 3.0 | |
646 */ | |
647 protected AnnotationModelEvent createAnnotationModelEvent() { | |
648 return new AnnotationModelEvent(this); | |
649 } | |
650 | |
651 /** | |
652 * Informs all annotation model listeners that this model has been changed | |
653 * as described in the annotation model event. The event is sent out | |
654 * to all listeners implementing <code>IAnnotationModelListenerExtension</code>. | |
655 * All other listeners are notified by just calling <code>modelChanged(IAnnotationModel)</code>. | |
656 * | |
657 * @param event the event to be sent out to the listeners | |
658 * @since 2.0 | |
659 */ | |
660 protected void fireModelChanged(AnnotationModelEvent event) { | |
661 | |
662 event.markSealed(); | |
663 | |
664 if (event.isEmpty()) | |
665 return; | |
666 | |
667 ArrayList v= new ArrayList(fAnnotationModelListeners); | |
668 Iterator e= v.iterator(); | |
669 while (e.hasNext()) { | |
134 | 670 IAnnotationModelListener l= cast(IAnnotationModelListener) e.next(); |
138 | 671 if ( cast(IAnnotationModelListenerExtension)l ) |
134 | 672 (cast(IAnnotationModelListenerExtension) l).modelChanged(event); |
129 | 673 else if (l !is null) |
674 l.modelChanged(this); | |
675 } | |
676 } | |
677 | |
678 /** | |
679 * Removes the given annotations from this model. If requested all | |
680 * annotation model listeners will be informed about this change. | |
681 * <code>modelInitiated</code> indicates whether the deletion has | |
682 * been initiated by this model or by one of its clients. | |
683 * | |
684 * @param annotations the annotations to be removed | |
685 * @param fireModelChanged indicates whether to notify all model listeners | |
686 * @param modelInitiated indicates whether this changes has been initiated by this model | |
687 */ | |
688 protected void removeAnnotations(List annotations, bool fireModelChanged, bool modelInitiated) { | |
689 if (annotations.size() > 0) { | |
690 Iterator e= annotations.iterator(); | |
691 while (e.hasNext()) | |
134 | 692 removeAnnotation(cast(Annotation) e.next(), false); |
129 | 693 |
694 if (fireModelChanged) | |
695 fireModelChanged(); | |
696 } | |
697 } | |
698 | |
699 /** | |
700 * Removes all annotations from the model whose associated positions have been | |
701 * deleted. If requested inform all model listeners about the change. | |
702 * | |
703 * @param fireModelChanged indicates whether to notify all model listeners | |
704 */ | |
705 protected void cleanup(bool fireModelChanged) { | |
706 cleanup(fireModelChanged, true); | |
707 } | |
708 | |
709 /** | |
710 * Removes all annotations from the model whose associated positions have been | |
711 * deleted. If requested inform all model listeners about the change. If requested | |
712 * a new thread is created for the notification of the model listeners. | |
713 * | |
714 * @param fireModelChanged indicates whether to notify all model listeners | |
715 * @param forkNotification <code>true</code> iff notification should be done in a new thread | |
716 * @since 3.0 | |
717 */ | |
718 private void cleanup(bool fireModelChanged, bool forkNotification) { | |
719 if (fDocumentChanged) { | |
720 fDocumentChanged= false; | |
721 | |
722 ArrayList deleted= new ArrayList(); | |
723 Iterator e= getAnnotationMap().keySetIterator(); | |
724 while (e.hasNext()) { | |
134 | 725 Annotation a= cast(Annotation) e.next(); |
726 Position p= cast(Position) fAnnotations.get(a); | |
129 | 727 if (p is null || p.isDeleted()) |
728 deleted.add(a); | |
729 } | |
730 | |
731 if (fireModelChanged && forkNotification) { | |
732 removeAnnotations(deleted, false, false); | |
733 synchronized (getLockObject()) { | |
734 if (fModelEvent !is null) | |
145 | 735 (new Thread ( &fireModelChanged() )).start(); |
129 | 736 } |
737 } else | |
738 removeAnnotations(deleted, fireModelChanged, false); | |
739 } | |
740 } | |
741 | |
742 /* | |
743 * @see dwtx.jface.text.source.IAnnotationModel#getAnnotationIterator() | |
744 */ | |
745 public Iterator getAnnotationIterator() { | |
746 return getAnnotationIterator(true, true); | |
747 } | |
748 | |
749 /** | |
750 * {@inheritDoc} | |
145 | 751 * |
129 | 752 * @since 3.4 |
753 */ | |
754 public Iterator getAnnotationIterator(int offset, int length, bool canStartBefore, bool canEndAfter) { | |
755 Iterator regionIterator= getRegionAnnotationIterator(offset, length, canStartBefore, canEndAfter); | |
145 | 756 |
129 | 757 if (fAttachments.isEmpty()) |
758 return regionIterator; | |
145 | 759 |
129 | 760 List iterators= new ArrayList(fAttachments.size() + 1); |
761 iterators.add(regionIterator); | |
762 Iterator it= fAttachments.keySet().iterator(); | |
763 while (it.hasNext()) { | |
134 | 764 IAnnotationModel attachment= cast(IAnnotationModel) fAttachments.get(it.next()); |
138 | 765 if ( cast(IAnnotationModelExtension2)attachment ) |
134 | 766 iterators.add((cast(IAnnotationModelExtension2) attachment).getAnnotationIterator(offset, length, canStartBefore, canEndAfter)); |
129 | 767 else |
768 iterators.add(new RegionIterator(attachment.getAnnotationIterator(), attachment, offset, length, canStartBefore, canEndAfter)); | |
769 } | |
145 | 770 |
129 | 771 return new MetaIterator(iterators.iterator()); |
772 } | |
145 | 773 |
129 | 774 /** |
775 * Returns an iterator as specified in {@link IAnnotationModelExtension2#getAnnotationIterator(int, int, bool, bool)} | |
145 | 776 * |
129 | 777 * @param offset region start |
778 * @param length region length | |
779 * @param canStartBefore position can start before region | |
780 * @param canEndAfter position can end after region | |
781 * @return an iterator to iterate over annotations in region | |
782 * @see IAnnotationModelExtension2#getAnnotationIterator(int, int, bool, bool) | |
783 * @since 3.4 | |
784 */ | |
785 private Iterator getRegionAnnotationIterator(int offset, int length, bool canStartBefore, bool canEndAfter) { | |
138 | 786 if (!( cast(AbstractDocument)fDocument )) |
129 | 787 return new RegionIterator(getAnnotationIterator(true), this, offset, length, canStartBefore, canEndAfter); |
145 | 788 |
134 | 789 AbstractDocument document= cast(AbstractDocument) fDocument; |
129 | 790 cleanup(true); |
145 | 791 |
129 | 792 try { |
793 Position[] positions= document.getPositions(IDocument.DEFAULT_CATEGORY, offset, length, canStartBefore, canEndAfter); | |
794 return new AnnotationsInterator(positions, fPositions); | |
795 } catch (BadPositionCategoryException e) { | |
796 //can not happen | |
797 Assert.isTrue(false); | |
798 return null; | |
799 } | |
800 } | |
801 | |
802 /** | |
803 * Returns all annotations managed by this model. <code>cleanup</code> | |
804 * indicates whether all annotations whose associated positions are | |
805 * deleted should previously be removed from the model. <code>recurse</code> indicates | |
806 * whether annotations of attached sub-models should also be returned. | |
807 * | |
808 * @param cleanup indicates whether annotations with deleted associated positions are removed | |
809 * @param recurse whether to return annotations managed by sub-models. | |
810 * @return all annotations managed by this model | |
811 * @since 3.0 | |
812 */ | |
813 private Iterator getAnnotationIterator(bool cleanup, bool recurse) { | |
814 Iterator iter= getAnnotationIterator(cleanup); | |
815 if (!recurse || fAttachments.isEmpty()) | |
816 return iter; | |
817 | |
818 List iterators= new ArrayList(fAttachments.size() + 1); | |
819 iterators.add(iter); | |
820 Iterator it= fAttachments.keySet().iterator(); | |
821 while (it.hasNext()) | |
134 | 822 iterators.add((cast(IAnnotationModel) fAttachments.get(it.next())).getAnnotationIterator()); |
129 | 823 |
824 return new MetaIterator(iterators.iterator()); | |
825 } | |
826 | |
827 /** | |
828 * Returns all annotations managed by this model. <code>cleanup</code> | |
829 * indicates whether all annotations whose associated positions are | |
830 * deleted should previously be removed from the model. | |
831 * | |
832 * @param cleanup indicates whether annotations with deleted associated positions are removed | |
833 * @return all annotations managed by this model | |
834 */ | |
835 protected Iterator getAnnotationIterator(bool cleanup) { | |
836 if (cleanup) | |
837 cleanup(true); | |
838 | |
839 return getAnnotationMap().keySetIterator(); | |
840 } | |
841 | |
842 /* | |
843 * @see dwtx.jface.text.source.IAnnotationModel#getPosition(dwtx.jface.text.source.Annotation) | |
844 */ | |
845 public Position getPosition(Annotation annotation) { | |
134 | 846 Position position= cast(Position) fAnnotations.get(annotation); |
129 | 847 if (position !is null) |
848 return position; | |
849 | |
850 Iterator it= fAttachments.values().iterator(); | |
851 while (position is null && it.hasNext()) | |
134 | 852 position= (cast(IAnnotationModel) it.next()).getPosition(annotation); |
129 | 853 return position; |
854 } | |
855 | |
856 /* | |
857 * @see dwtx.jface.text.source.IAnnotationModelExtension#removeAllAnnotations() | |
858 * @since 3.0 | |
859 */ | |
860 public void removeAllAnnotations() { | |
861 removeAllAnnotations(true); | |
862 } | |
863 | |
864 /** | |
865 * Removes all annotations from the annotation model. If requested | |
866 * inform all model change listeners about this change. | |
867 * | |
868 * @param fireModelChanged indicates whether to notify all model listeners | |
869 */ | |
870 protected void removeAllAnnotations(bool fireModelChanged) { | |
871 | |
872 if (fDocument !is null) { | |
873 Iterator e= getAnnotationMap().keySetIterator(); | |
874 while (e.hasNext()) { | |
134 | 875 Annotation a= cast(Annotation) e.next(); |
876 Position p= cast(Position) fAnnotations.get(a); | |
129 | 877 removePosition(fDocument, p); |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
878 // p.delete_(); |
129 | 879 synchronized (getLockObject()) { |
880 getAnnotationModelEvent().annotationRemoved(a, p); | |
881 } | |
882 } | |
883 } | |
884 | |
885 fAnnotations.clear(); | |
886 fPositions.clear(); | |
887 | |
888 if (fireModelChanged) | |
889 fireModelChanged(); | |
890 } | |
891 | |
892 /* | |
893 * @see dwtx.jface.text.source.IAnnotationModel#removeAnnotation(dwtx.jface.text.source.Annotation) | |
894 */ | |
895 public void removeAnnotation(Annotation annotation) { | |
896 removeAnnotation(annotation, true); | |
897 } | |
898 | |
899 /** | |
900 * Removes the given annotation from the annotation model. | |
901 * If requested inform all model change listeners about this change. | |
902 * | |
903 * @param annotation the annotation to be removed | |
904 * @param fireModelChanged indicates whether to notify all model listeners | |
905 */ | |
906 protected void removeAnnotation(Annotation annotation, bool fireModelChanged) { | |
907 if (fAnnotations.containsKey(annotation)) { | |
908 | |
909 Position p= null; | |
134 | 910 p= cast(Position) fAnnotations.get(annotation); |
129 | 911 if (fDocument !is null) { |
912 removePosition(fDocument, p); | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
913 // p.delete_(); |
129 | 914 } |
915 | |
916 fAnnotations.remove(annotation); | |
917 fPositions.remove(p); | |
918 synchronized (getLockObject()) { | |
919 getAnnotationModelEvent().annotationRemoved(annotation, p); | |
920 } | |
921 | |
922 if (fireModelChanged) | |
923 fireModelChanged(); | |
924 } | |
925 } | |
926 | |
927 /* | |
928 * @see dwtx.jface.text.source.IAnnotationModelExtension#modifyAnnotationPosition(dwtx.jface.text.source.Annotation, dwtx.jface.text.Position) | |
929 * @since 3.0 | |
930 */ | |
931 public void modifyAnnotationPosition(Annotation annotation, Position position) { | |
932 modifyAnnotationPosition(annotation, position, true); | |
933 } | |
934 | |
935 /** | |
936 * Modifies the associated position of the given annotation to the given | |
937 * position. If the annotation is not yet managed by this annotation model, | |
938 * the annotation is added. When the position is <code>null</code>, the | |
939 * annotation is removed from the model. | |
940 * <p> | |
941 * If requested, all annotation model change listeners will be informed | |
942 * about the change. | |
943 * | |
944 * @param annotation the annotation whose associated position should be | |
945 * modified | |
946 * @param position the position to whose values the associated position | |
947 * should be changed | |
948 * @param fireModelChanged indicates whether to notify all model listeners | |
949 * @since 3.0 | |
950 */ | |
951 protected void modifyAnnotationPosition(Annotation annotation, Position position, bool fireModelChanged) { | |
952 if (position is null) { | |
953 removeAnnotation(annotation, fireModelChanged); | |
954 } else { | |
134 | 955 Position p= cast(Position) fAnnotations.get(annotation); |
129 | 956 if (p !is null) { |
957 | |
958 if (position.getOffset() !is p.getOffset() || position.getLength() !is p.getLength()) { | |
959 fDocument.removePosition(p); | |
960 p.setOffset(position.getOffset()); | |
961 p.setLength(position.getLength()); | |
962 try { | |
963 fDocument.addPosition(p); | |
964 } catch (BadLocationException e) { | |
965 // ignore invalid position | |
966 } | |
967 } | |
968 synchronized (getLockObject()) { | |
969 getAnnotationModelEvent().annotationChanged(annotation); | |
970 } | |
971 if (fireModelChanged) | |
972 fireModelChanged(); | |
973 | |
974 } else { | |
975 try { | |
976 addAnnotation(annotation, position, fireModelChanged); | |
977 } catch (BadLocationException x) { | |
978 // ignore invalid position | |
979 } | |
980 } | |
981 } | |
982 } | |
983 | |
984 /** | |
985 * Modifies the given annotation if the annotation is managed by this | |
986 * annotation model. | |
987 * <p> | |
988 * If requested, all annotation model change listeners will be informed | |
989 * about the change. | |
990 * | |
991 * @param annotation the annotation to be modified | |
992 * @param fireModelChanged indicates whether to notify all model listeners | |
993 * @since 3.0 | |
994 */ | |
995 protected void modifyAnnotation(Annotation annotation, bool fireModelChanged) { | |
996 if (fAnnotations.containsKey(annotation)) { | |
997 synchronized (getLockObject()) { | |
998 getAnnotationModelEvent().annotationChanged(annotation); | |
999 } | |
1000 if (fireModelChanged) | |
1001 fireModelChanged(); | |
1002 } | |
1003 } | |
1004 | |
1005 /* | |
1006 * @see IAnnotationModel#removeAnnotationModelListener(IAnnotationModelListener) | |
1007 */ | |
1008 public void removeAnnotationModelListener(IAnnotationModelListener listener) { | |
1009 fAnnotationModelListeners.remove(listener); | |
1010 } | |
1011 | |
1012 /* | |
1013 * @see dwtx.jface.text.source.IAnnotationModelExtension#attach(java.lang.Object, java.lang.Object) | |
1014 * @since 3.0 | |
1015 */ | |
1016 public void addAnnotationModel(Object key, IAnnotationModel attachment) { | |
1017 Assert.isNotNull(attachment); | |
1018 if (!fAttachments.containsValue(attachment)) { | |
1019 fAttachments.put(key, attachment); | |
1020 for (int i= 0; i < fOpenConnections; i++) | |
1021 attachment.connect(fDocument); | |
1022 attachment.addAnnotationModelListener(fModelListener); | |
1023 } | |
1024 } | |
1025 | |
1026 /* | |
1027 * @see dwtx.jface.text.source.IAnnotationModelExtension#get(java.lang.Object) | |
1028 * @since 3.0 | |
1029 */ | |
1030 public IAnnotationModel getAnnotationModel(Object key) { | |
134 | 1031 return cast(IAnnotationModel) fAttachments.get(key); |
129 | 1032 } |
1033 | |
1034 /* | |
1035 * @see dwtx.jface.text.source.IAnnotationModelExtension#detach(java.lang.Object) | |
1036 * @since 3.0 | |
1037 */ | |
1038 public IAnnotationModel removeAnnotationModel(Object key) { | |
134 | 1039 IAnnotationModel ret= cast(IAnnotationModel) fAttachments.remove(key); |
129 | 1040 if (ret !is null) { |
1041 for (int i= 0; i < fOpenConnections; i++) | |
1042 ret.disconnect(fDocument); | |
1043 ret.removeAnnotationModelListener(fModelListener); | |
1044 } | |
1045 return ret; | |
1046 } | |
1047 | |
1048 /* | |
1049 * @see dwtx.jface.text.source.IAnnotationModelExtension#getModificationStamp() | |
1050 * @since 3.0 | |
1051 */ | |
1052 public Object getModificationStamp() { | |
1053 return fModificationStamp; | |
1054 } | |
1055 } |