Mercurial > projects > dwt-addons
annotate dwtx/jface/text/source/AnnotationModel.d @ 159:7926b636c282
...
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Wed, 27 Aug 2008 01:57:58 +0200 |
parents | 25f1f92fa3df |
children | 1a5b8f8129df |
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 */ | |
159 | 352 private IAnnotationModelListener fModelListener; |
129 | 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 */ | |
159 | 362 private Object fModificationStamp; |
129 | 363 /** |
364 * Creates a new annotation model. The annotation is empty, i.e. does not | |
365 * manage any annotations and is not connected to any document. | |
366 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
367 public this() { |
159 | 368 fModelListener= new InternalModelListener(); |
369 fModificationStamp= new Object(); | |
129 | 370 fAnnotations= new AnnotationMap(10); |
371 fPositions= new IdentityHashMap(10); | |
372 fAnnotationModelListeners= new ArrayList(2); | |
373 | |
135 | 374 fDocumentListener= new class() IDocumentListener { |
129 | 375 |
376 public void documentAboutToBeChanged(DocumentEvent event) { | |
377 } | |
378 | |
379 public void documentChanged(DocumentEvent event) { | |
380 fDocumentChanged= true; | |
381 } | |
382 }; | |
383 } | |
384 | |
385 /** | |
386 * Returns the annotation map internally used by this annotation model. | |
387 * | |
388 * @return the annotation map internally used by this annotation model | |
389 * @since 3.0 | |
390 */ | |
391 protected IAnnotationMap getAnnotationMap() { | |
134 | 392 return cast(IAnnotationMap) fAnnotations; |
129 | 393 } |
394 | |
395 /* | |
396 * @see dwtx.jface.text.ISynchronizable#getLockObject() | |
397 * @since 3.0 | |
398 */ | |
399 public Object getLockObject() { | |
400 return getAnnotationMap().getLockObject(); | |
401 } | |
402 | |
403 /* | |
404 * @see dwtx.jface.text.ISynchronizable#setLockObject(java.lang.Object) | |
405 * @since 3.0 | |
406 */ | |
407 public void setLockObject(Object lockObject) { | |
408 getAnnotationMap().setLockObject(lockObject); | |
409 } | |
410 | |
411 /** | |
412 * Returns the current annotation model event. This is the event that will be sent out | |
413 * when calling <code>fireModelChanged</code>. | |
414 * | |
415 * @return the current annotation model event | |
416 * @since 3.0 | |
417 */ | |
418 protected final AnnotationModelEvent getAnnotationModelEvent() { | |
419 synchronized (getLockObject()) { | |
420 if (fModelEvent is null) { | |
421 fModelEvent= createAnnotationModelEvent(); | |
422 fModelEvent.markWorldChange(false); | |
423 fModificationStamp= fModelEvent; | |
424 } | |
425 return fModelEvent; | |
426 } | |
427 } | |
428 | |
429 /* | |
430 * @see dwtx.jface.text.source.IAnnotationModel#addAnnotation(dwtx.jface.text.source.Annotation, dwtx.jface.text.Position) | |
431 */ | |
432 public void addAnnotation(Annotation annotation, Position position) { | |
433 try { | |
434 addAnnotation(annotation, position, true); | |
435 } catch (BadLocationException e) { | |
436 // ignore invalid position | |
437 } | |
438 } | |
439 | |
440 /* | |
441 * @see dwtx.jface.text.source.IAnnotationModelExtension#replaceAnnotations(dwtx.jface.text.source.Annotation[], java.util.Map) | |
442 * @since 3.0 | |
443 */ | |
444 public void replaceAnnotations(Annotation[] annotationsToRemove, Map annotationsToAdd) { | |
445 try { | |
446 replaceAnnotations(annotationsToRemove, annotationsToAdd, true); | |
447 } catch (BadLocationException x) { | |
448 } | |
449 } | |
450 | |
451 /** | |
452 * Replaces the given annotations in this model and if advised fires a | |
453 * model change event. | |
454 * | |
455 * @param annotationsToRemove the annotations to be removed | |
456 * @param annotationsToAdd the annotations to be added | |
457 * @param fireModelChanged <code>true</code> if a model change event | |
458 * should be fired, <code>false</code> otherwise | |
459 * @throws BadLocationException in case an annotation should be added at an | |
460 * invalid position | |
461 * @since 3.0 | |
462 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
463 protected void replaceAnnotations(Annotation[] annotationsToRemove, Map annotationsToAdd, bool fireModelChanged) { |
129 | 464 |
465 if (annotationsToRemove !is null) { | |
466 for (int i= 0, length= annotationsToRemove.length; i < length; i++) | |
467 removeAnnotation(annotationsToRemove[i], false); | |
468 } | |
469 | |
470 if (annotationsToAdd !is null) { | |
471 Iterator iter= annotationsToAdd.entrySet().iterator(); | |
472 while (iter.hasNext()) { | |
157
7f75eaa8103a
volatile and cast Map.Entry
Frank Benoit <benoit@tionex.de>
parents:
153
diff
changeset
|
473 Map.Entry mapEntry= cast(Map.Entry) iter.next(); |
134 | 474 Annotation annotation= cast(Annotation) mapEntry.getKey(); |
475 Position position= cast(Position) mapEntry.getValue(); | |
129 | 476 addAnnotation(annotation, position, false); |
477 } | |
478 } | |
479 | |
480 if (fireModelChanged) | |
481 fireModelChanged(); | |
482 } | |
483 | |
484 /** | |
485 * Adds the given annotation to this model. Associates the | |
486 * annotation with the given position. If requested, all annotation | |
487 * model listeners are informed about this model change. If the annotation | |
488 * is already managed by this model nothing happens. | |
489 * | |
490 * @param annotation the annotation to add | |
491 * @param position the associate position | |
492 * @param fireModelChanged indicates whether to notify all model listeners | |
493 * @throws BadLocationException if the position is not a valid document position | |
494 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
495 protected void addAnnotation(Annotation annotation, Position position, bool fireModelChanged) { |
129 | 496 if (!fAnnotations.containsKey(annotation)) { |
497 | |
498 addPosition(fDocument, position); | |
499 fAnnotations.put(annotation, position); | |
500 fPositions.put(position, annotation); | |
501 synchronized (getLockObject()) { | |
502 getAnnotationModelEvent().annotationAdded(annotation); | |
503 } | |
504 | |
505 if (fireModelChanged) | |
506 fireModelChanged(); | |
507 } | |
508 } | |
509 | |
510 /* | |
511 * @see dwtx.jface.text.source.IAnnotationModel#addAnnotationModelListener(dwtx.jface.text.source.IAnnotationModelListener) | |
512 */ | |
513 public void addAnnotationModelListener(IAnnotationModelListener listener) { | |
514 if (!fAnnotationModelListeners.contains(listener)) { | |
515 fAnnotationModelListeners.add(listener); | |
138 | 516 if ( cast(IAnnotationModelListenerExtension)listener ) { |
134 | 517 IAnnotationModelListenerExtension extension= cast(IAnnotationModelListenerExtension) listener; |
129 | 518 AnnotationModelEvent event= createAnnotationModelEvent(); |
519 event.markSealed(); | |
520 extension.modelChanged(event); | |
521 } else | |
522 listener.modelChanged(this); | |
523 } | |
524 } | |
525 | |
526 /** | |
527 * Adds the given position to the default position category of the | |
528 * given document. | |
529 * | |
530 * @param document the document to which to add the position | |
531 * @param position the position to add | |
532 * @throws BadLocationException if the position is not a valid document position | |
533 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
534 protected void addPosition(IDocument document, Position position) { |
129 | 535 if (document !is null) |
536 document.addPosition(position); | |
537 } | |
538 | |
539 /** | |
540 * Removes the given position from the default position category of the | |
541 * given document. | |
542 * | |
543 * @param document the document to which to add the position | |
544 * @param position the position to add | |
545 * | |
546 * @since 3.0 | |
547 */ | |
548 protected void removePosition(IDocument document, Position position) { | |
549 if (document !is null) | |
550 document.removePosition(position); | |
551 } | |
552 | |
553 /* | |
554 * @see dwtx.jface.text.source.IAnnotationModel#connect(dwtx.jface.text.IDocument) | |
555 */ | |
556 public void connect(IDocument document) { | |
557 Assert.isTrue(fDocument is null || fDocument is document); | |
558 | |
559 if (fDocument is null) { | |
560 fDocument= document; | |
561 Iterator e= getAnnotationMap().valuesIterator(); | |
562 while (e.hasNext()) | |
563 try { | |
134 | 564 addPosition(fDocument, cast(Position) e.next()); |
129 | 565 } catch (BadLocationException x) { |
566 // ignore invalid position | |
567 } | |
568 } | |
569 | |
570 ++ fOpenConnections; | |
571 if (fOpenConnections is 1) { | |
572 fDocument.addDocumentListener(fDocumentListener); | |
573 connected(); | |
574 } | |
575 | |
576 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { | |
134 | 577 IAnnotationModel model= cast(IAnnotationModel) fAttachments.get(it.next()); |
129 | 578 model.connect(document); |
579 } | |
580 } | |
581 | |
582 /** | |
583 * Hook method. Is called as soon as this model becomes connected to a document. | |
584 * Subclasses may re-implement. | |
585 */ | |
586 protected void connected() { | |
587 } | |
588 | |
589 /** | |
590 * Hook method. Is called as soon as this model becomes disconnected from its document. | |
591 * Subclasses may re-implement. | |
592 */ | |
593 protected void disconnected() { | |
594 } | |
595 | |
596 /* | |
597 * @see dwtx.jface.text.source.IAnnotationModel#disconnect(dwtx.jface.text.IDocument) | |
598 */ | |
599 public void disconnect(IDocument document) { | |
600 | |
601 Assert.isTrue(fDocument is document); | |
602 | |
603 for (Iterator it= fAttachments.keySet().iterator(); it.hasNext();) { | |
134 | 604 IAnnotationModel model= cast(IAnnotationModel) fAttachments.get(it.next()); |
129 | 605 model.disconnect(document); |
606 } | |
607 | |
608 -- fOpenConnections; | |
609 if (fOpenConnections is 0) { | |
610 | |
611 disconnected(); | |
612 fDocument.removeDocumentListener(fDocumentListener); | |
613 | |
614 if (fDocument !is null) { | |
615 Iterator e= getAnnotationMap().valuesIterator(); | |
616 while (e.hasNext()) { | |
134 | 617 Position p= cast(Position) e.next(); |
129 | 618 removePosition(fDocument, p); |
619 } | |
620 fDocument= null; | |
621 } | |
622 } | |
623 } | |
624 | |
625 /** | |
626 * Informs all annotation model listeners that this model has been changed. | |
627 */ | |
628 protected void fireModelChanged() { | |
629 AnnotationModelEvent modelEvent= null; | |
630 | |
631 synchronized(getLockObject()) { | |
632 if (fModelEvent !is null) { | |
633 modelEvent= fModelEvent; | |
634 fModelEvent= null; | |
635 } | |
636 } | |
637 | |
638 if (modelEvent !is null) | |
639 fireModelChanged(modelEvent); | |
640 } | |
641 | |
642 /** | |
643 * Creates and returns a new annotation model event. Subclasses may override. | |
644 * | |
645 * @return a new and empty annotation model event | |
646 * @since 3.0 | |
647 */ | |
648 protected AnnotationModelEvent createAnnotationModelEvent() { | |
649 return new AnnotationModelEvent(this); | |
650 } | |
651 | |
652 /** | |
653 * Informs all annotation model listeners that this model has been changed | |
654 * as described in the annotation model event. The event is sent out | |
655 * to all listeners implementing <code>IAnnotationModelListenerExtension</code>. | |
656 * All other listeners are notified by just calling <code>modelChanged(IAnnotationModel)</code>. | |
657 * | |
658 * @param event the event to be sent out to the listeners | |
659 * @since 2.0 | |
660 */ | |
661 protected void fireModelChanged(AnnotationModelEvent event) { | |
662 | |
663 event.markSealed(); | |
664 | |
665 if (event.isEmpty()) | |
666 return; | |
667 | |
668 ArrayList v= new ArrayList(fAnnotationModelListeners); | |
669 Iterator e= v.iterator(); | |
670 while (e.hasNext()) { | |
134 | 671 IAnnotationModelListener l= cast(IAnnotationModelListener) e.next(); |
138 | 672 if ( cast(IAnnotationModelListenerExtension)l ) |
134 | 673 (cast(IAnnotationModelListenerExtension) l).modelChanged(event); |
129 | 674 else if (l !is null) |
675 l.modelChanged(this); | |
676 } | |
677 } | |
678 | |
679 /** | |
680 * Removes the given annotations from this model. If requested all | |
681 * annotation model listeners will be informed about this change. | |
682 * <code>modelInitiated</code> indicates whether the deletion has | |
683 * been initiated by this model or by one of its clients. | |
684 * | |
685 * @param annotations the annotations to be removed | |
686 * @param fireModelChanged indicates whether to notify all model listeners | |
687 * @param modelInitiated indicates whether this changes has been initiated by this model | |
688 */ | |
689 protected void removeAnnotations(List annotations, bool fireModelChanged, bool modelInitiated) { | |
690 if (annotations.size() > 0) { | |
691 Iterator e= annotations.iterator(); | |
692 while (e.hasNext()) | |
134 | 693 removeAnnotation(cast(Annotation) e.next(), false); |
129 | 694 |
695 if (fireModelChanged) | |
696 fireModelChanged(); | |
697 } | |
698 } | |
699 | |
700 /** | |
701 * Removes all annotations from the model whose associated positions have been | |
702 * deleted. If requested inform all model listeners about the change. | |
703 * | |
704 * @param fireModelChanged indicates whether to notify all model listeners | |
705 */ | |
706 protected void cleanup(bool fireModelChanged) { | |
707 cleanup(fireModelChanged, true); | |
708 } | |
709 | |
710 /** | |
711 * Removes all annotations from the model whose associated positions have been | |
712 * deleted. If requested inform all model listeners about the change. If requested | |
713 * a new thread is created for the notification of the model listeners. | |
714 * | |
715 * @param fireModelChanged indicates whether to notify all model listeners | |
716 * @param forkNotification <code>true</code> iff notification should be done in a new thread | |
717 * @since 3.0 | |
718 */ | |
719 private void cleanup(bool fireModelChanged, bool forkNotification) { | |
720 if (fDocumentChanged) { | |
721 fDocumentChanged= false; | |
722 | |
723 ArrayList deleted= new ArrayList(); | |
724 Iterator e= getAnnotationMap().keySetIterator(); | |
725 while (e.hasNext()) { | |
134 | 726 Annotation a= cast(Annotation) e.next(); |
727 Position p= cast(Position) fAnnotations.get(a); | |
129 | 728 if (p is null || p.isDeleted()) |
729 deleted.add(a); | |
730 } | |
731 | |
732 if (fireModelChanged && forkNotification) { | |
733 removeAnnotations(deleted, false, false); | |
734 synchronized (getLockObject()) { | |
735 if (fModelEvent !is null) | |
145 | 736 (new Thread ( &fireModelChanged() )).start(); |
129 | 737 } |
738 } else | |
739 removeAnnotations(deleted, fireModelChanged, false); | |
740 } | |
741 } | |
742 | |
743 /* | |
744 * @see dwtx.jface.text.source.IAnnotationModel#getAnnotationIterator() | |
745 */ | |
746 public Iterator getAnnotationIterator() { | |
747 return getAnnotationIterator(true, true); | |
748 } | |
749 | |
750 /** | |
751 * {@inheritDoc} | |
145 | 752 * |
129 | 753 * @since 3.4 |
754 */ | |
755 public Iterator getAnnotationIterator(int offset, int length, bool canStartBefore, bool canEndAfter) { | |
756 Iterator regionIterator= getRegionAnnotationIterator(offset, length, canStartBefore, canEndAfter); | |
145 | 757 |
129 | 758 if (fAttachments.isEmpty()) |
759 return regionIterator; | |
145 | 760 |
129 | 761 List iterators= new ArrayList(fAttachments.size() + 1); |
762 iterators.add(regionIterator); | |
763 Iterator it= fAttachments.keySet().iterator(); | |
764 while (it.hasNext()) { | |
134 | 765 IAnnotationModel attachment= cast(IAnnotationModel) fAttachments.get(it.next()); |
138 | 766 if ( cast(IAnnotationModelExtension2)attachment ) |
134 | 767 iterators.add((cast(IAnnotationModelExtension2) attachment).getAnnotationIterator(offset, length, canStartBefore, canEndAfter)); |
129 | 768 else |
769 iterators.add(new RegionIterator(attachment.getAnnotationIterator(), attachment, offset, length, canStartBefore, canEndAfter)); | |
770 } | |
145 | 771 |
129 | 772 return new MetaIterator(iterators.iterator()); |
773 } | |
145 | 774 |
129 | 775 /** |
776 * Returns an iterator as specified in {@link IAnnotationModelExtension2#getAnnotationIterator(int, int, bool, bool)} | |
145 | 777 * |
129 | 778 * @param offset region start |
779 * @param length region length | |
780 * @param canStartBefore position can start before region | |
781 * @param canEndAfter position can end after region | |
782 * @return an iterator to iterate over annotations in region | |
783 * @see IAnnotationModelExtension2#getAnnotationIterator(int, int, bool, bool) | |
784 * @since 3.4 | |
785 */ | |
786 private Iterator getRegionAnnotationIterator(int offset, int length, bool canStartBefore, bool canEndAfter) { | |
138 | 787 if (!( cast(AbstractDocument)fDocument )) |
129 | 788 return new RegionIterator(getAnnotationIterator(true), this, offset, length, canStartBefore, canEndAfter); |
145 | 789 |
134 | 790 AbstractDocument document= cast(AbstractDocument) fDocument; |
129 | 791 cleanup(true); |
145 | 792 |
129 | 793 try { |
794 Position[] positions= document.getPositions(IDocument.DEFAULT_CATEGORY, offset, length, canStartBefore, canEndAfter); | |
795 return new AnnotationsInterator(positions, fPositions); | |
796 } catch (BadPositionCategoryException e) { | |
797 //can not happen | |
798 Assert.isTrue(false); | |
799 return null; | |
800 } | |
801 } | |
802 | |
803 /** | |
804 * Returns all annotations managed by this model. <code>cleanup</code> | |
805 * indicates whether all annotations whose associated positions are | |
806 * deleted should previously be removed from the model. <code>recurse</code> indicates | |
807 * whether annotations of attached sub-models should also be returned. | |
808 * | |
809 * @param cleanup indicates whether annotations with deleted associated positions are removed | |
810 * @param recurse whether to return annotations managed by sub-models. | |
811 * @return all annotations managed by this model | |
812 * @since 3.0 | |
813 */ | |
814 private Iterator getAnnotationIterator(bool cleanup, bool recurse) { | |
815 Iterator iter= getAnnotationIterator(cleanup); | |
816 if (!recurse || fAttachments.isEmpty()) | |
817 return iter; | |
818 | |
819 List iterators= new ArrayList(fAttachments.size() + 1); | |
820 iterators.add(iter); | |
821 Iterator it= fAttachments.keySet().iterator(); | |
822 while (it.hasNext()) | |
134 | 823 iterators.add((cast(IAnnotationModel) fAttachments.get(it.next())).getAnnotationIterator()); |
129 | 824 |
825 return new MetaIterator(iterators.iterator()); | |
826 } | |
827 | |
828 /** | |
829 * Returns all annotations managed by this model. <code>cleanup</code> | |
830 * indicates whether all annotations whose associated positions are | |
831 * deleted should previously be removed from the model. | |
832 * | |
833 * @param cleanup indicates whether annotations with deleted associated positions are removed | |
834 * @return all annotations managed by this model | |
835 */ | |
836 protected Iterator getAnnotationIterator(bool cleanup) { | |
837 if (cleanup) | |
838 cleanup(true); | |
839 | |
840 return getAnnotationMap().keySetIterator(); | |
841 } | |
842 | |
843 /* | |
844 * @see dwtx.jface.text.source.IAnnotationModel#getPosition(dwtx.jface.text.source.Annotation) | |
845 */ | |
846 public Position getPosition(Annotation annotation) { | |
134 | 847 Position position= cast(Position) fAnnotations.get(annotation); |
129 | 848 if (position !is null) |
849 return position; | |
850 | |
851 Iterator it= fAttachments.values().iterator(); | |
852 while (position is null && it.hasNext()) | |
134 | 853 position= (cast(IAnnotationModel) it.next()).getPosition(annotation); |
129 | 854 return position; |
855 } | |
856 | |
857 /* | |
858 * @see dwtx.jface.text.source.IAnnotationModelExtension#removeAllAnnotations() | |
859 * @since 3.0 | |
860 */ | |
861 public void removeAllAnnotations() { | |
862 removeAllAnnotations(true); | |
863 } | |
864 | |
865 /** | |
866 * Removes all annotations from the annotation model. If requested | |
867 * inform all model change listeners about this change. | |
868 * | |
869 * @param fireModelChanged indicates whether to notify all model listeners | |
870 */ | |
871 protected void removeAllAnnotations(bool fireModelChanged) { | |
872 | |
873 if (fDocument !is null) { | |
874 Iterator e= getAnnotationMap().keySetIterator(); | |
875 while (e.hasNext()) { | |
134 | 876 Annotation a= cast(Annotation) e.next(); |
877 Position p= cast(Position) fAnnotations.get(a); | |
129 | 878 removePosition(fDocument, p); |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
879 // p.delete_(); |
129 | 880 synchronized (getLockObject()) { |
881 getAnnotationModelEvent().annotationRemoved(a, p); | |
882 } | |
883 } | |
884 } | |
885 | |
886 fAnnotations.clear(); | |
887 fPositions.clear(); | |
888 | |
889 if (fireModelChanged) | |
890 fireModelChanged(); | |
891 } | |
892 | |
893 /* | |
894 * @see dwtx.jface.text.source.IAnnotationModel#removeAnnotation(dwtx.jface.text.source.Annotation) | |
895 */ | |
896 public void removeAnnotation(Annotation annotation) { | |
897 removeAnnotation(annotation, true); | |
898 } | |
899 | |
900 /** | |
901 * Removes the given annotation from the annotation model. | |
902 * If requested inform all model change listeners about this change. | |
903 * | |
904 * @param annotation the annotation to be removed | |
905 * @param fireModelChanged indicates whether to notify all model listeners | |
906 */ | |
907 protected void removeAnnotation(Annotation annotation, bool fireModelChanged) { | |
908 if (fAnnotations.containsKey(annotation)) { | |
909 | |
910 Position p= null; | |
134 | 911 p= cast(Position) fAnnotations.get(annotation); |
129 | 912 if (fDocument !is null) { |
913 removePosition(fDocument, p); | |
140
26688fec6d23
Following dsss compile errors
Frank Benoit <benoit@tionex.de>
parents:
138
diff
changeset
|
914 // p.delete_(); |
129 | 915 } |
916 | |
917 fAnnotations.remove(annotation); | |
918 fPositions.remove(p); | |
919 synchronized (getLockObject()) { | |
920 getAnnotationModelEvent().annotationRemoved(annotation, p); | |
921 } | |
922 | |
923 if (fireModelChanged) | |
924 fireModelChanged(); | |
925 } | |
926 } | |
927 | |
928 /* | |
929 * @see dwtx.jface.text.source.IAnnotationModelExtension#modifyAnnotationPosition(dwtx.jface.text.source.Annotation, dwtx.jface.text.Position) | |
930 * @since 3.0 | |
931 */ | |
932 public void modifyAnnotationPosition(Annotation annotation, Position position) { | |
933 modifyAnnotationPosition(annotation, position, true); | |
934 } | |
935 | |
936 /** | |
937 * Modifies the associated position of the given annotation to the given | |
938 * position. If the annotation is not yet managed by this annotation model, | |
939 * the annotation is added. When the position is <code>null</code>, the | |
940 * annotation is removed from the model. | |
941 * <p> | |
942 * If requested, all annotation model change listeners will be informed | |
943 * about the change. | |
944 * | |
945 * @param annotation the annotation whose associated position should be | |
946 * modified | |
947 * @param position the position to whose values the associated position | |
948 * should be changed | |
949 * @param fireModelChanged indicates whether to notify all model listeners | |
950 * @since 3.0 | |
951 */ | |
952 protected void modifyAnnotationPosition(Annotation annotation, Position position, bool fireModelChanged) { | |
953 if (position is null) { | |
954 removeAnnotation(annotation, fireModelChanged); | |
955 } else { | |
134 | 956 Position p= cast(Position) fAnnotations.get(annotation); |
129 | 957 if (p !is null) { |
958 | |
959 if (position.getOffset() !is p.getOffset() || position.getLength() !is p.getLength()) { | |
960 fDocument.removePosition(p); | |
961 p.setOffset(position.getOffset()); | |
962 p.setLength(position.getLength()); | |
963 try { | |
964 fDocument.addPosition(p); | |
965 } catch (BadLocationException e) { | |
966 // ignore invalid position | |
967 } | |
968 } | |
969 synchronized (getLockObject()) { | |
970 getAnnotationModelEvent().annotationChanged(annotation); | |
971 } | |
972 if (fireModelChanged) | |
973 fireModelChanged(); | |
974 | |
975 } else { | |
976 try { | |
977 addAnnotation(annotation, position, fireModelChanged); | |
978 } catch (BadLocationException x) { | |
979 // ignore invalid position | |
980 } | |
981 } | |
982 } | |
983 } | |
984 | |
985 /** | |
986 * Modifies the given annotation if the annotation is managed by this | |
987 * annotation model. | |
988 * <p> | |
989 * If requested, all annotation model change listeners will be informed | |
990 * about the change. | |
991 * | |
992 * @param annotation the annotation to be modified | |
993 * @param fireModelChanged indicates whether to notify all model listeners | |
994 * @since 3.0 | |
995 */ | |
996 protected void modifyAnnotation(Annotation annotation, bool fireModelChanged) { | |
997 if (fAnnotations.containsKey(annotation)) { | |
998 synchronized (getLockObject()) { | |
999 getAnnotationModelEvent().annotationChanged(annotation); | |
1000 } | |
1001 if (fireModelChanged) | |
1002 fireModelChanged(); | |
1003 } | |
1004 } | |
1005 | |
1006 /* | |
1007 * @see IAnnotationModel#removeAnnotationModelListener(IAnnotationModelListener) | |
1008 */ | |
1009 public void removeAnnotationModelListener(IAnnotationModelListener listener) { | |
1010 fAnnotationModelListeners.remove(listener); | |
1011 } | |
1012 | |
1013 /* | |
1014 * @see dwtx.jface.text.source.IAnnotationModelExtension#attach(java.lang.Object, java.lang.Object) | |
1015 * @since 3.0 | |
1016 */ | |
1017 public void addAnnotationModel(Object key, IAnnotationModel attachment) { | |
1018 Assert.isNotNull(attachment); | |
1019 if (!fAttachments.containsValue(attachment)) { | |
1020 fAttachments.put(key, attachment); | |
1021 for (int i= 0; i < fOpenConnections; i++) | |
1022 attachment.connect(fDocument); | |
1023 attachment.addAnnotationModelListener(fModelListener); | |
1024 } | |
1025 } | |
1026 | |
1027 /* | |
1028 * @see dwtx.jface.text.source.IAnnotationModelExtension#get(java.lang.Object) | |
1029 * @since 3.0 | |
1030 */ | |
1031 public IAnnotationModel getAnnotationModel(Object key) { | |
134 | 1032 return cast(IAnnotationModel) fAttachments.get(key); |
129 | 1033 } |
1034 | |
1035 /* | |
1036 * @see dwtx.jface.text.source.IAnnotationModelExtension#detach(java.lang.Object) | |
1037 * @since 3.0 | |
1038 */ | |
1039 public IAnnotationModel removeAnnotationModel(Object key) { | |
134 | 1040 IAnnotationModel ret= cast(IAnnotationModel) fAttachments.remove(key); |
129 | 1041 if (ret !is null) { |
1042 for (int i= 0; i < fOpenConnections; i++) | |
1043 ret.disconnect(fDocument); | |
1044 ret.removeAnnotationModelListener(fModelListener); | |
1045 } | |
1046 return ret; | |
1047 } | |
1048 | |
1049 /* | |
1050 * @see dwtx.jface.text.source.IAnnotationModelExtension#getModificationStamp() | |
1051 * @since 3.0 | |
1052 */ | |
1053 public Object getModificationStamp() { | |
1054 return fModificationStamp; | |
1055 } | |
1056 } |