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