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