001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jface.text.source;
011:
012: import java.util.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.NoSuchElementException;
018:
019: import org.eclipse.core.runtime.Assert;
020:
021: import org.eclipse.jface.text.BadLocationException;
022: import org.eclipse.jface.text.DocumentEvent;
023: import org.eclipse.jface.text.IDocument;
024: import org.eclipse.jface.text.IDocumentListener;
025: import org.eclipse.jface.text.ISynchronizable;
026: import org.eclipse.jface.text.Position;
027:
028: /**
029: * Standard implementation of {@link IAnnotationModel} and its extension
030: * interfaces. This class can directly be used by clients. Subclasses may adapt
031: * this annotation model to other existing annotation mechanisms. This class
032: * also implements {@link org.eclipse.jface.text.ISynchronizable}. All
033: * modifications of the model's internal annotation map are synchronized using
034: * the model's lock object.
035: */
036: public class AnnotationModel implements IAnnotationModel,
037: IAnnotationModelExtension, ISynchronizable {
038:
039: /**
040: * A single iterator builds its behavior based on a sequence of iterators.
041: *
042: * @since 3.1
043: */
044: private static class MetaIterator implements Iterator {
045:
046: /** The iterator over a list of iterators. */
047: private Iterator fSuperIterator;
048: /** The current iterator. */
049: private Iterator fCurrent;
050: /** The current element. */
051: private Object fCurrentElement;
052:
053: public MetaIterator(Iterator iterator) {
054: fSuperIterator = iterator;
055: fCurrent = (Iterator) fSuperIterator.next(); // there is at least one.
056: }
057:
058: public void remove() {
059: throw new UnsupportedOperationException();
060: }
061:
062: public boolean hasNext() {
063: if (fCurrentElement != null)
064: return true;
065:
066: if (fCurrent.hasNext()) {
067: fCurrentElement = fCurrent.next();
068: return true;
069: } else if (fSuperIterator.hasNext()) {
070: fCurrent = (Iterator) fSuperIterator.next();
071: return hasNext();
072: } else
073: return false;
074: }
075:
076: public Object next() {
077: if (!hasNext())
078: throw new NoSuchElementException();
079:
080: Object element = fCurrentElement;
081: fCurrentElement = null;
082: return element;
083: }
084: }
085:
086: /**
087: * Internal annotation model listener for forwarding annotation model changes from the attached models to the
088: * registered listeners of the outer most annotation model.
089: *
090: * @since 3.0
091: */
092: private class InternalModelListener implements
093: IAnnotationModelListener, IAnnotationModelListenerExtension {
094:
095: /*
096: * @see org.eclipse.jface.text.source.IAnnotationModelListener#modelChanged(org.eclipse.jface.text.source.IAnnotationModel)
097: */
098: public void modelChanged(IAnnotationModel model) {
099: AnnotationModel.this
100: .fireModelChanged(new AnnotationModelEvent(model,
101: true));
102: }
103:
104: /*
105: * @see org.eclipse.jface.text.source.IAnnotationModelListenerExtension#modelChanged(org.eclipse.jface.text.source.AnnotationModelEvent)
106: */
107: public void modelChanged(AnnotationModelEvent event) {
108: AnnotationModel.this .fireModelChanged(event);
109: }
110: }
111:
112: /**
113: * The list of managed annotations
114: * @deprecated since 3.0 use <code>getAnnotationMap</code> instead
115: */
116: protected Map fAnnotations;
117: /** The list of annotation model listeners */
118: protected ArrayList fAnnotationModelListeners;
119: /** The document connected with this model */
120: protected IDocument fDocument;
121: /** The number of open connections to the same document */
122: private int fOpenConnections = 0;
123: /** The document listener for tracking whether document positions might have been changed. */
124: private IDocumentListener fDocumentListener;
125: /** The flag indicating whether the document positions might have been changed. */
126: private boolean fDocumentChanged = true;
127: /**
128: * The model's attachment.
129: * @since 3.0
130: */
131: private Map fAttachments = new HashMap();
132: /**
133: * The annotation model listener on attached sub-models.
134: * @since 3.0
135: */
136: private IAnnotationModelListener fModelListener = new InternalModelListener();
137: /**
138: * The current annotation model event.
139: * @since 3.0
140: */
141: private AnnotationModelEvent fModelEvent;
142: /**
143: * The modification stamp.
144: * @since 3.0
145: */
146: private Object fModificationStamp = new Object();
147:
148: /**
149: * Creates a new annotation model. The annotation is empty, i.e. does not
150: * manage any annotations and is not connected to any document.
151: */
152: public AnnotationModel() {
153: fAnnotations = new AnnotationMap(10);
154: fAnnotationModelListeners = new ArrayList(2);
155:
156: fDocumentListener = new IDocumentListener() {
157:
158: public void documentAboutToBeChanged(DocumentEvent event) {
159: }
160:
161: public void documentChanged(DocumentEvent event) {
162: fDocumentChanged = true;
163: }
164: };
165: }
166:
167: /**
168: * Returns the annotation map internally used by this annotation model.
169: *
170: * @return the annotation map internally used by this annotation model
171: * @since 3.0
172: */
173: protected IAnnotationMap getAnnotationMap() {
174: return (IAnnotationMap) fAnnotations;
175: }
176:
177: /*
178: * @see org.eclipse.jface.text.ISynchronizable#getLockObject()
179: * @since 3.0
180: */
181: public Object getLockObject() {
182: return getAnnotationMap().getLockObject();
183: }
184:
185: /*
186: * @see org.eclipse.jface.text.ISynchronizable#setLockObject(java.lang.Object)
187: * @since 3.0
188: */
189: public void setLockObject(Object lockObject) {
190: getAnnotationMap().setLockObject(lockObject);
191: }
192:
193: /**
194: * Returns the current annotation model event. This is the event that will be sent out
195: * when calling <code>fireModelChanged</code>.
196: *
197: * @return the current annotation model event
198: * @since 3.0
199: */
200: protected final AnnotationModelEvent getAnnotationModelEvent() {
201: synchronized (getLockObject()) {
202: if (fModelEvent == null) {
203: fModelEvent = createAnnotationModelEvent();
204: fModelEvent.markWorldChange(false);
205: fModificationStamp = fModelEvent;
206: }
207: return fModelEvent;
208: }
209: }
210:
211: /*
212: * @see org.eclipse.jface.text.source.IAnnotationModel#addAnnotation(org.eclipse.jface.text.source.Annotation, org.eclipse.jface.text.Position)
213: */
214: public void addAnnotation(Annotation annotation, Position position) {
215: try {
216: addAnnotation(annotation, position, true);
217: } catch (BadLocationException e) {
218: // ignore invalid position
219: }
220: }
221:
222: /*
223: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#replaceAnnotations(org.eclipse.jface.text.source.Annotation[], java.util.Map)
224: * @since 3.0
225: */
226: public void replaceAnnotations(Annotation[] annotationsToRemove,
227: Map annotationsToAdd) {
228: try {
229: replaceAnnotations(annotationsToRemove, annotationsToAdd,
230: true);
231: } catch (BadLocationException x) {
232: }
233: }
234:
235: /**
236: * Replaces the given annotations in this model and if advised fires a
237: * model change event.
238: *
239: * @param annotationsToRemove the annotations to be removed
240: * @param annotationsToAdd the annotations to be added
241: * @param fireModelChanged <code>true</code> if a model change event
242: * should be fired, <code>false</code> otherwise
243: * @throws BadLocationException in case an annotation should be added at an
244: * invalid position
245: * @since 3.0
246: */
247: protected void replaceAnnotations(Annotation[] annotationsToRemove,
248: Map annotationsToAdd, boolean fireModelChanged)
249: throws BadLocationException {
250:
251: if (annotationsToRemove != null) {
252: for (int i = 0, length = annotationsToRemove.length; i < length; i++)
253: removeAnnotation(annotationsToRemove[i], false);
254: }
255:
256: if (annotationsToAdd != null) {
257: Iterator iter = annotationsToAdd.entrySet().iterator();
258: while (iter.hasNext()) {
259: Map.Entry mapEntry = (Map.Entry) iter.next();
260: Annotation annotation = (Annotation) mapEntry.getKey();
261: Position position = (Position) mapEntry.getValue();
262: addAnnotation(annotation, position, false);
263: }
264: }
265:
266: if (fireModelChanged)
267: fireModelChanged();
268: }
269:
270: /**
271: * Adds the given annotation to this model. Associates the
272: * annotation with the given position. If requested, all annotation
273: * model listeners are informed about this model change. If the annotation
274: * is already managed by this model nothing happens.
275: *
276: * @param annotation the annotation to add
277: * @param position the associate position
278: * @param fireModelChanged indicates whether to notify all model listeners
279: * @throws BadLocationException if the position is not a valid document position
280: */
281: protected void addAnnotation(Annotation annotation,
282: Position position, boolean fireModelChanged)
283: throws BadLocationException {
284: if (!fAnnotations.containsKey(annotation)) {
285:
286: addPosition(fDocument, position);
287: fAnnotations.put(annotation, position);
288: synchronized (getLockObject()) {
289: getAnnotationModelEvent().annotationAdded(annotation);
290: }
291:
292: if (fireModelChanged)
293: fireModelChanged();
294: }
295: }
296:
297: /*
298: * @see org.eclipse.jface.text.source.IAnnotationModel#addAnnotationModelListener(org.eclipse.jface.text.source.IAnnotationModelListener)
299: */
300: public void addAnnotationModelListener(
301: IAnnotationModelListener listener) {
302: if (!fAnnotationModelListeners.contains(listener)) {
303: fAnnotationModelListeners.add(listener);
304: if (listener instanceof IAnnotationModelListenerExtension) {
305: IAnnotationModelListenerExtension extension = (IAnnotationModelListenerExtension) listener;
306: AnnotationModelEvent event = createAnnotationModelEvent();
307: event.markSealed();
308: extension.modelChanged(event);
309: } else
310: listener.modelChanged(this );
311: }
312: }
313:
314: /**
315: * Adds the given position to the default position category of the
316: * given document.
317: *
318: * @param document the document to which to add the position
319: * @param position the position to add
320: * @throws BadLocationException if the position is not a valid document position
321: */
322: protected void addPosition(IDocument document, Position position)
323: throws BadLocationException {
324: if (document != null)
325: document.addPosition(position);
326: }
327:
328: /**
329: * Removes the given position from the default position category of the
330: * given document.
331: *
332: * @param document the document to which to add the position
333: * @param position the position to add
334: *
335: * @since 3.0
336: */
337: protected void removePosition(IDocument document, Position position) {
338: if (document != null)
339: document.removePosition(position);
340: }
341:
342: /*
343: * @see org.eclipse.jface.text.source.IAnnotationModel#connect(org.eclipse.jface.text.IDocument)
344: */
345: public void connect(IDocument document) {
346: Assert.isTrue(fDocument == null || fDocument == document);
347:
348: if (fDocument == null) {
349: fDocument = document;
350: Iterator e = getAnnotationMap().valuesIterator();
351: while (e.hasNext())
352: try {
353: addPosition(fDocument, (Position) e.next());
354: } catch (BadLocationException x) {
355: // ignore invalid position
356: }
357: }
358:
359: ++fOpenConnections;
360: if (fOpenConnections == 1) {
361: fDocument.addDocumentListener(fDocumentListener);
362: connected();
363: }
364:
365: for (Iterator it = fAttachments.keySet().iterator(); it
366: .hasNext();) {
367: IAnnotationModel model = (IAnnotationModel) fAttachments
368: .get(it.next());
369: model.connect(document);
370: }
371: }
372:
373: /**
374: * Hook method. Is called as soon as this model becomes connected to a document.
375: * Subclasses may re-implement.
376: */
377: protected void connected() {
378: }
379:
380: /**
381: * Hook method. Is called as soon as this model becomes disconnected from its document.
382: * Subclasses may re-implement.
383: */
384: protected void disconnected() {
385: }
386:
387: /*
388: * @see org.eclipse.jface.text.source.IAnnotationModel#disconnect(org.eclipse.jface.text.IDocument)
389: */
390: public void disconnect(IDocument document) {
391:
392: Assert.isTrue(fDocument == document);
393:
394: for (Iterator it = fAttachments.keySet().iterator(); it
395: .hasNext();) {
396: IAnnotationModel model = (IAnnotationModel) fAttachments
397: .get(it.next());
398: model.disconnect(document);
399: }
400:
401: --fOpenConnections;
402: if (fOpenConnections == 0) {
403:
404: disconnected();
405: fDocument.removeDocumentListener(fDocumentListener);
406:
407: if (fDocument != null) {
408: Iterator e = getAnnotationMap().valuesIterator();
409: while (e.hasNext()) {
410: Position p = (Position) e.next();
411: removePosition(fDocument, p);
412: }
413: fDocument = null;
414: }
415: }
416: }
417:
418: /**
419: * Informs all annotation model listeners that this model has been changed.
420: */
421: protected void fireModelChanged() {
422: AnnotationModelEvent modelEvent = null;
423:
424: synchronized (getLockObject()) {
425: if (fModelEvent != null) {
426: modelEvent = fModelEvent;
427: fModelEvent = null;
428: }
429: }
430:
431: if (modelEvent != null)
432: fireModelChanged(modelEvent);
433: }
434:
435: /**
436: * Creates and returns a new annotation model event. Subclasses may override.
437: *
438: * @return a new and empty annotation model event
439: * @since 3.0
440: */
441: protected AnnotationModelEvent createAnnotationModelEvent() {
442: return new AnnotationModelEvent(this );
443: }
444:
445: /**
446: * Informs all annotation model listeners that this model has been changed
447: * as described in the annotation model event. The event is sent out
448: * to all listeners implementing <code>IAnnotationModelListenerExtension</code>.
449: * All other listeners are notified by just calling <code>modelChanged(IAnnotationModel)</code>.
450: *
451: * @param event the event to be sent out to the listeners
452: * @since 2.0
453: */
454: protected void fireModelChanged(AnnotationModelEvent event) {
455:
456: event.markSealed();
457:
458: if (event.isEmpty())
459: return;
460:
461: ArrayList v = new ArrayList(fAnnotationModelListeners);
462: Iterator e = v.iterator();
463: while (e.hasNext()) {
464: IAnnotationModelListener l = (IAnnotationModelListener) e
465: .next();
466: if (l instanceof IAnnotationModelListenerExtension)
467: ((IAnnotationModelListenerExtension) l)
468: .modelChanged(event);
469: else if (l != null)
470: l.modelChanged(this );
471: }
472: }
473:
474: /**
475: * Removes the given annotations from this model. If requested all
476: * annotation model listeners will be informed about this change.
477: * <code>modelInitiated</code> indicates whether the deletion has
478: * been initiated by this model or by one of its clients.
479: *
480: * @param annotations the annotations to be removed
481: * @param fireModelChanged indicates whether to notify all model listeners
482: * @param modelInitiated indicates whether this changes has been initiated by this model
483: */
484: protected void removeAnnotations(List annotations,
485: boolean fireModelChanged, boolean modelInitiated) {
486: if (annotations.size() > 0) {
487: Iterator e = annotations.iterator();
488: while (e.hasNext())
489: removeAnnotation((Annotation) e.next(), false);
490:
491: if (fireModelChanged)
492: fireModelChanged();
493: }
494: }
495:
496: /**
497: * Removes all annotations from the model whose associated positions have been
498: * deleted. If requested inform all model listeners about the change.
499: *
500: * @param fireModelChanged indicates whether to notify all model listeners
501: */
502: protected void cleanup(boolean fireModelChanged) {
503: cleanup(fireModelChanged, true);
504: }
505:
506: /**
507: * Removes all annotations from the model whose associated positions have been
508: * deleted. If requested inform all model listeners about the change. If requested
509: * a new thread is created for the notification of the model listeners.
510: *
511: * @param fireModelChanged indicates whether to notify all model listeners
512: * @param forkNotification <code>true</code> iff notification should be done in a new thread
513: * @since 3.0
514: */
515: private void cleanup(boolean fireModelChanged,
516: boolean forkNotification) {
517: if (fDocumentChanged) {
518: fDocumentChanged = false;
519:
520: ArrayList deleted = new ArrayList();
521: Iterator e = getAnnotationMap().keySetIterator();
522: while (e.hasNext()) {
523: Annotation a = (Annotation) e.next();
524: Position p = (Position) fAnnotations.get(a);
525: if (p == null || p.isDeleted())
526: deleted.add(a);
527: }
528:
529: if (fireModelChanged && forkNotification) {
530: removeAnnotations(deleted, false, false);
531: synchronized (getLockObject()) {
532: if (fModelEvent != null)
533: new Thread() {
534: public void run() {
535: fireModelChanged();
536: }
537: }.start();
538: }
539: } else
540: removeAnnotations(deleted, fireModelChanged, false);
541: }
542: }
543:
544: /*
545: * @see org.eclipse.jface.text.source.IAnnotationModel#getAnnotationIterator()
546: */
547: public Iterator getAnnotationIterator() {
548: return getAnnotationIterator(true, true);
549: }
550:
551: /**
552: * Returns all annotations managed by this model. <code>cleanup</code>
553: * indicates whether all annotations whose associated positions are
554: * deleted should previously be removed from the model. <code>recurse</code> indicates
555: * whether annotations of attached sub-models should also be returned.
556: *
557: * @param cleanup indicates whether annotations with deleted associated positions are removed
558: * @param recurse whether to return annotations managed by sub-models.
559: * @return all annotations managed by this model
560: * @since 3.0
561: */
562: private Iterator getAnnotationIterator(boolean cleanup,
563: boolean recurse) {
564:
565: if (!recurse || fAttachments.isEmpty())
566: return getAnnotationIterator(cleanup);
567:
568: List iterators = new ArrayList(fAttachments.size() + 1);
569: iterators.add(getAnnotationIterator(cleanup));
570: for (Iterator it = fAttachments.keySet().iterator(); it
571: .hasNext();) {
572: iterators.add(((IAnnotationModel) fAttachments.get(it
573: .next())).getAnnotationIterator());
574: }
575:
576: return new MetaIterator(iterators.iterator());
577: }
578:
579: /**
580: * Returns all annotations managed by this model. <code>cleanup</code>
581: * indicates whether all annotations whose associated positions are
582: * deleted should previously be removed from the model.
583: *
584: * @param cleanup indicates whether annotations with deleted associated positions are removed
585: * @return all annotations managed by this model
586: */
587: protected Iterator getAnnotationIterator(boolean cleanup) {
588: if (cleanup)
589: cleanup(true);
590:
591: return getAnnotationMap().keySetIterator();
592: }
593:
594: /*
595: * @see org.eclipse.jface.text.source.IAnnotationModel#getPosition(org.eclipse.jface.text.source.Annotation)
596: */
597: public Position getPosition(Annotation annotation) {
598: Position position = (Position) fAnnotations.get(annotation);
599: if (position != null)
600: return position;
601:
602: Iterator it = fAttachments.values().iterator();
603: while (position == null && it.hasNext())
604: position = ((IAnnotationModel) it.next())
605: .getPosition(annotation);
606: return position;
607: }
608:
609: /*
610: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#removeAllAnnotations()
611: * @since 3.0
612: */
613: public void removeAllAnnotations() {
614: removeAllAnnotations(true);
615: }
616:
617: /**
618: * Removes all annotations from the annotation model. If requested
619: * inform all model change listeners about this change.
620: *
621: * @param fireModelChanged indicates whether to notify all model listeners
622: */
623: protected void removeAllAnnotations(boolean fireModelChanged) {
624:
625: if (fDocument != null) {
626: Iterator e = getAnnotationMap().keySetIterator();
627: while (e.hasNext()) {
628: Annotation a = (Annotation) e.next();
629: Position p = (Position) fAnnotations.get(a);
630: removePosition(fDocument, p);
631: // p.delete();
632: synchronized (getLockObject()) {
633: getAnnotationModelEvent().annotationRemoved(a, p);
634: }
635: }
636: }
637:
638: fAnnotations.clear();
639:
640: if (fireModelChanged)
641: fireModelChanged();
642: }
643:
644: /*
645: * @see org.eclipse.jface.text.source.IAnnotationModel#removeAnnotation(org.eclipse.jface.text.source.Annotation)
646: */
647: public void removeAnnotation(Annotation annotation) {
648: removeAnnotation(annotation, true);
649: }
650:
651: /**
652: * Removes the given annotation from the annotation model.
653: * If requested inform all model change listeners about this change.
654: *
655: * @param annotation the annotation to be removed
656: * @param fireModelChanged indicates whether to notify all model listeners
657: */
658: protected void removeAnnotation(Annotation annotation,
659: boolean fireModelChanged) {
660: if (fAnnotations.containsKey(annotation)) {
661:
662: Position p = null;
663: if (fDocument != null) {
664: p = (Position) fAnnotations.get(annotation);
665: removePosition(fDocument, p);
666: // p.delete();
667: }
668:
669: fAnnotations.remove(annotation);
670: synchronized (getLockObject()) {
671: getAnnotationModelEvent().annotationRemoved(annotation,
672: p);
673: }
674:
675: if (fireModelChanged)
676: fireModelChanged();
677: }
678: }
679:
680: /*
681: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#modifyAnnotationPosition(org.eclipse.jface.text.source.Annotation, org.eclipse.jface.text.Position)
682: * @since 3.0
683: */
684: public void modifyAnnotationPosition(Annotation annotation,
685: Position position) {
686: modifyAnnotationPosition(annotation, position, true);
687: }
688:
689: /**
690: * Modifies the associated position of the given annotation to the given
691: * position. If the annotation is not yet managed by this annotation model,
692: * the annotation is added. When the position is <code>null</code>, the
693: * annotation is removed from the model.
694: * <p>
695: * If requested, all annotation model change listeners will be informed
696: * about the change.
697: *
698: * @param annotation the annotation whose associated position should be
699: * modified
700: * @param position the position to whose values the associated position
701: * should be changed
702: * @param fireModelChanged indicates whether to notify all model listeners
703: * @since 3.0
704: */
705: protected void modifyAnnotationPosition(Annotation annotation,
706: Position position, boolean fireModelChanged) {
707: if (position == null) {
708: removeAnnotation(annotation, fireModelChanged);
709: } else {
710: Position p = (Position) fAnnotations.get(annotation);
711: if (p != null) {
712:
713: if (position.getOffset() != p.getOffset()
714: || position.getLength() != p.getLength()) {
715: p.setOffset(position.getOffset());
716: p.setLength(position.getLength());
717: }
718: synchronized (getLockObject()) {
719: getAnnotationModelEvent().annotationChanged(
720: annotation);
721: }
722: if (fireModelChanged)
723: fireModelChanged();
724:
725: } else {
726: try {
727: addAnnotation(annotation, position,
728: fireModelChanged);
729: } catch (BadLocationException x) {
730: // ignore invalid position
731: }
732: }
733: }
734: }
735:
736: /**
737: * Modifies the given annotation if the annotation is managed by this
738: * annotation model.
739: * <p>
740: * If requested, all annotation model change listeners will be informed
741: * about the change.
742: *
743: * @param annotation the annotation to be modified
744: * @param fireModelChanged indicates whether to notify all model listeners
745: * @since 3.0
746: */
747: protected void modifyAnnotation(Annotation annotation,
748: boolean fireModelChanged) {
749: if (fAnnotations.containsKey(annotation)) {
750: synchronized (getLockObject()) {
751: getAnnotationModelEvent().annotationChanged(annotation);
752: }
753: if (fireModelChanged)
754: fireModelChanged();
755: }
756: }
757:
758: /*
759: * @see IAnnotationModel#removeAnnotationModelListener(IAnnotationModelListener)
760: */
761: public void removeAnnotationModelListener(
762: IAnnotationModelListener listener) {
763: fAnnotationModelListeners.remove(listener);
764: }
765:
766: /*
767: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#attach(java.lang.Object, java.lang.Object)
768: * @since 3.0
769: */
770: public void addAnnotationModel(Object key,
771: IAnnotationModel attachment) {
772: Assert.isNotNull(attachment);
773: if (!fAttachments.containsValue(attachment)) {
774: fAttachments.put(key, attachment);
775: for (int i = 0; i < fOpenConnections; i++)
776: attachment.connect(fDocument);
777: attachment.addAnnotationModelListener(fModelListener);
778: }
779: }
780:
781: /*
782: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#get(java.lang.Object)
783: * @since 3.0
784: */
785: public IAnnotationModel getAnnotationModel(Object key) {
786: return (IAnnotationModel) fAttachments.get(key);
787: }
788:
789: /*
790: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#detach(java.lang.Object)
791: * @since 3.0
792: */
793: public IAnnotationModel removeAnnotationModel(Object key) {
794: IAnnotationModel ret = (IAnnotationModel) fAttachments
795: .remove(key);
796: if (ret != null) {
797: for (int i = 0; i < fOpenConnections; i++)
798: ret.disconnect(fDocument);
799: ret.removeAnnotationModelListener(fModelListener);
800: }
801: return ret;
802: }
803:
804: /*
805: * @see org.eclipse.jface.text.source.IAnnotationModelExtension#getModificationStamp()
806: * @since 3.0
807: */
808: public Object getModificationStamp() {
809: return fModificationStamp;
810: }
811: }
|