KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > link > LinkedModeModel


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11 package org.eclipse.jface.text.link;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.core.runtime.Assert;
22
23 import org.eclipse.text.edits.MalformedTreeException;
24 import org.eclipse.text.edits.TextEdit;
25
26 import org.eclipse.jface.text.BadLocationException;
27 import org.eclipse.jface.text.BadPositionCategoryException;
28 import org.eclipse.jface.text.DocumentEvent;
29 import org.eclipse.jface.text.IDocument;
30 import org.eclipse.jface.text.IDocumentExtension;
31 import org.eclipse.jface.text.IDocumentListener;
32 import org.eclipse.jface.text.IPositionUpdater;
33 import org.eclipse.jface.text.Position;
34 import org.eclipse.jface.text.IDocumentExtension.IReplace;
35
36 /**
37  * The model for linked mode, umbrellas several
38  * {@link LinkedPositionGroup}s. Once installed, the model
39  * propagates any changes to a position to all its siblings in the same position
40  * group.
41  * <p>
42  * Setting up a model consists of first adding
43  * <code>LinkedPositionGroup</code>s to it, and then installing the
44  * model by either calling {@link #forceInstall()} or
45  * {@link #tryInstall()}. After installing the model, it becomes
46  * <em>sealed</em> and no more groups may be added.
47  * </p>
48  * <p>
49  * If a document change occurs that would modify more than one position
50  * group or that would invalidate the disjointness requirement of the positions,
51  * the model is torn down and all positions are deleted. The same happens
52  * upon calling {@link #exit(int)}.
53  * </p>
54  * <h4>Nesting</h4>
55  * <p>
56  * A <code>LinkedModeModel</code> may be nested into another model. This
57  * happens when installing a model the positions of which all fit into a
58  * single position in a parent model that has previously been installed on
59  * the same document(s).
60  * </p>
61  * <p>
62  * Clients may instantiate instances of this class.
63  * </p>
64  *
65  * @since 3.0
66  */

67 public class LinkedModeModel {
68
69     /**
70      * Checks whether there is already a model installed on <code>document</code>.
71      *
72      * @param document the <code>IDocument</code> of interest
73      * @return <code>true</code> if there is an existing model, <code>false</code>
74      * otherwise
75      */

76     public static boolean hasInstalledModel(IDocument document) {
77         // if there is a manager, there also is a model
78
return LinkedModeManager.hasManager(document);
79     }
80
81     /**
82      * Checks whether there is already a linked mode model installed on any of
83      * the <code>documents</code>.
84      *
85      * @param documents the <code>IDocument</code>s of interest
86      * @return <code>true</code> if there is an existing model, <code>false</code>
87      * otherwise
88      */

89     public static boolean hasInstalledModel(IDocument[] documents) {
90         // if there is a manager, there also is a model
91
return LinkedModeManager.hasManager(documents);
92     }
93
94     /**
95      * Cancels any linked mode model on the specified document. If there is no
96      * model, nothing happens.
97      *
98      * @param document the document whose <code>LinkedModeModel</code> should
99      * be canceled
100      */

101     public static void closeAllModels(IDocument document) {
102         LinkedModeManager.cancelManager(document);
103     }
104
105     /**
106      * Returns the model currently active on <code>document</code> at
107      * <code>offset</code>, or <code>null</code> if there is none.
108      *
109      * @param document the document for which the caller asks for a
110      * model
111      * @param offset the offset into <code>document</code>, as there may be
112      * several models on a document
113      * @return the model currently active on <code>document</code>, or
114      * <code>null</code>
115      */

116     public static LinkedModeModel getModel(IDocument document, int offset) {
117         if (!hasInstalledModel(document))
118             return null;
119         
120         LinkedModeManager mgr= LinkedModeManager.getLinkedManager(new IDocument[] {document}, false);
121         if (mgr != null)
122             return mgr.getTopEnvironment();
123         return null;
124     }
125
126     /**
127      * Encapsulates the edition triggered by a change to a linking position. Can
128      * be applied to a document as a whole.
129      */

130     private class Replace implements IReplace {
131
132         /** The edition to apply on a document. */
133         private TextEdit fEdit;
134
135         /**
136          * Creates a new instance.
137          *
138          * @param edit the edition to apply to a document.
139          */

140         public Replace(TextEdit edit) {
141             fEdit= edit;
142         }
143
144         /*
145          * @see org.eclipse.jface.text.IDocumentExtension.IReplace#perform(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocumentListener)
146          */

147         public void perform(IDocument document, IDocumentListener owner) throws RuntimeException JavaDoc, MalformedTreeException {
148             document.removeDocumentListener(owner);
149             fIsChanging= true;
150             try {
151                 fEdit.apply(document, TextEdit.UPDATE_REGIONS | TextEdit.CREATE_UNDO);
152             } catch (BadLocationException e) {
153                 /* XXX: perform should really throw a BadLocationException
154                  * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52950
155                  */

156                 throw new RuntimeException JavaDoc(e);
157             } finally {
158                 document.addDocumentListener(owner);
159                 fIsChanging= false;
160             }
161         }
162
163     }
164
165     /**
166      * The document listener triggering the linked updating of positions
167      * managed by this model.
168      */

169     private class DocumentListener implements IDocumentListener {
170
171         private boolean fExit= false;
172
173         /**
174          * Checks whether <code>event</code> occurs within any of the positions
175          * managed by this model. If not, the linked mode is left.
176          *
177          * @param event {@inheritDoc}
178          */

179         public void documentAboutToBeChanged(DocumentEvent event) {
180             // don't react on changes executed by the parent model
181
if (fParentEnvironment != null && fParentEnvironment.isChanging())
182                 return;
183
184             for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
185                 LinkedPositionGroup group= (LinkedPositionGroup) it.next();
186                 if (!group.isLegalEvent(event)) {
187                     fExit= true;
188                     return;
189                 }
190             }
191         }
192
193         /**
194          * Propagates a change to a linked position to all its sibling positions.
195          *
196          * @param event {@inheritDoc}
197          */

198         public void documentChanged(DocumentEvent event) {
199             if (fExit) {
200                 LinkedModeModel.this.exit(ILinkedModeListener.EXTERNAL_MODIFICATION);
201                 return;
202             }
203             fExit= false;
204
205             // don't react on changes executed by the parent model
206
if (fParentEnvironment != null && fParentEnvironment.isChanging())
207                 return;
208
209             // collect all results
210
Map JavaDoc result= null;
211             for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext();) {
212                 LinkedPositionGroup group= (LinkedPositionGroup) it.next();
213
214                 Map JavaDoc map= group.handleEvent(event);
215                 if (result != null && map != null) {
216                     // exit if more than one position was changed
217
LinkedModeModel.this.exit(ILinkedModeListener.EXTERNAL_MODIFICATION);
218                     return;
219                 }
220                 if (map != null)
221                     result= map;
222             }
223
224             if (result != null) {
225                 // edit all documents
226
for (Iterator JavaDoc it2= result.keySet().iterator(); it2.hasNext(); ) {
227                     IDocument doc= (IDocument) it2.next();
228                     TextEdit edit= (TextEdit) result.get(doc);
229                     Replace replace= new Replace(edit);
230
231                     // apply the edition, either as post notification replace
232
// on the calling document or directly on any other
233
// document
234
if (doc == event.getDocument()) {
235                         if (doc instanceof IDocumentExtension) {
236                             ((IDocumentExtension) doc).registerPostNotificationReplace(this, replace);
237                         } else {
238                             // ignore - there is no way we can log from JFace text...
239
}
240                     } else {
241                         replace.perform(doc, this);
242                     }
243                 }
244             }
245         }
246
247     }
248
249     /** The set of linked position groups. */
250     private final List JavaDoc fGroups= new ArrayList JavaDoc();
251     /** The set of documents spanned by this group. */
252     private final Set JavaDoc fDocuments= new HashSet JavaDoc();
253     /** The position updater for linked positions. */
254     private final IPositionUpdater fUpdater= new InclusivePositionUpdater(getCategory());
255     /** The document listener on the documents affected by this model. */
256     private final DocumentListener fDocumentListener= new DocumentListener();
257     /** The parent model for a hierarchical set up, or <code>null</code>. */
258     private LinkedModeModel fParentEnvironment;
259     /**
260      * The position in <code>fParentEnvironment</code> that includes all
261      * positions in this object, or <code>null</code> if there is no parent
262      * model.
263      */

264     private LinkedPosition fParentPosition= null;
265     /**
266      * A model is sealed once it has children - no more positions can be
267      * added.
268      */

269     private boolean fIsSealed= false;
270     /** <code>true</code> when this model is changing documents. */
271     private boolean fIsChanging= false;
272     /** The linked listeners. */
273     private final List JavaDoc fListeners= new ArrayList JavaDoc();
274     /** Flag telling whether we have exited: */
275     private boolean fIsActive= true;
276     /**
277      * The sequence of document positions as we are going to iterate through
278      * them.
279      */

280     private List JavaDoc fPositionSequence= new ArrayList JavaDoc();
281
282     /**
283      * Whether we are in the process of editing documents (set by <code>Replace</code>,
284      * read by <code>DocumentListener</code>.
285      *
286      * @return <code>true</code> if we are in the process of editing a
287      * document, <code>false</code> otherwise
288      */

289     private boolean isChanging() {
290         return fIsChanging || fParentEnvironment != null && fParentEnvironment.isChanging();
291     }
292
293     /**
294      * Throws a <code>BadLocationException</code> if <code>group</code>
295      * conflicts with this model's groups.
296      *
297      * @param group the group being checked
298      * @throws BadLocationException if <code>group</code> conflicts with this
299      * model's groups
300      */

301     private void enforceDisjoint(LinkedPositionGroup group) throws BadLocationException {
302         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
303             LinkedPositionGroup g= (LinkedPositionGroup) it.next();
304             g.enforceDisjoint(group);
305         }
306     }
307
308     /**
309      * Causes this model to exit. Called either if an illegal document change
310      * is detected, or by the UI.
311      *
312      * @param flags the exit flags as defined in {@link ILinkedModeListener}
313      */

314     public void exit(int flags) {
315         if (!fIsActive)
316             return;
317
318         fIsActive= false;
319
320         for (Iterator JavaDoc it= fDocuments.iterator(); it.hasNext(); ) {
321             IDocument doc= (IDocument) it.next();
322             try {
323                 doc.removePositionCategory(getCategory());
324             } catch (BadPositionCategoryException e) {
325                 // won't happen
326
Assert.isTrue(false);
327             }
328             doc.removePositionUpdater(fUpdater);
329             doc.removeDocumentListener(fDocumentListener);
330         }
331
332         fDocuments.clear();
333         fGroups.clear();
334
335         List JavaDoc listeners= new ArrayList JavaDoc(fListeners);
336         fListeners.clear();
337         for (Iterator JavaDoc it= listeners.iterator(); it.hasNext(); ) {
338             ILinkedModeListener listener= (ILinkedModeListener) it.next();
339             listener.left(this, flags);
340         }
341
342
343         if (fParentEnvironment != null)
344             fParentEnvironment.resume(flags);
345     }
346
347     /**
348      * Causes this model to stop forwarding updates. The positions are not
349      * unregistered however, which will only happen when <code>exit</code>
350      * is called, or after the next document change.
351      *
352      * @param flags the exit flags as defined in {@link ILinkedModeListener}
353      * @since 3.1
354      */

355     public void stopForwarding(int flags) {
356         fDocumentListener.fExit= true;
357     }
358
359     /**
360      * Puts <code>document</code> into the set of managed documents. This
361      * involves registering the document listener and adding our position
362      * category.
363      *
364      * @param document the new document
365      */

366     private void manageDocument(IDocument document) {
367         if (!fDocuments.contains(document)) {
368             fDocuments.add(document);
369             document.addPositionCategory(getCategory());
370             document.addPositionUpdater(fUpdater);
371             document.addDocumentListener(fDocumentListener);
372         }
373
374     }
375
376     /**
377      * Returns the position category used by this model.
378      *
379      * @return the position category used by this model
380      */

381     private String JavaDoc getCategory() {
382         return toString();
383     }
384
385     /**
386      * Adds a position group to this <code>LinkedModeModel</code>. This
387      * method may not be called if the model has been installed. Also, if
388      * a UI has been set up for this model, it may not pick up groups
389      * added afterwards.
390      * <p>
391      * If the positions in <code>group</code> conflict with any other group in
392      * this model, a <code>BadLocationException</code> is thrown. Also,
393      * if this model is nested inside another one, all positions in all
394      * groups of the child model have to reside within a single position in the
395      * parent model, otherwise a <code>BadLocationException</code> is thrown.
396      * </p>
397      * <p>
398      * If <code>group</code> already exists, nothing happens.
399      * </p>
400      *
401      * @param group the group to be added to this model
402      * @throws BadLocationException if the group conflicts with the other groups
403      * in this model or violates the nesting requirements.
404      * @throws IllegalStateException if the method is called when the
405      * model is already sealed
406      */

407     public void addGroup(LinkedPositionGroup group) throws BadLocationException {
408         if (group == null)
409             throw new IllegalArgumentException JavaDoc("group may not be null"); //$NON-NLS-1$
410
if (fIsSealed)
411             throw new IllegalStateException JavaDoc("model is already installed"); //$NON-NLS-1$
412
if (fGroups.contains(group))
413             // nothing happens
414
return;
415
416         enforceDisjoint(group);
417         group.seal();
418         fGroups.add(group);
419     }
420
421     /**
422      * Creates a new model.
423      * @since 3.1
424      */

425     public LinkedModeModel() {
426     }
427
428     /**
429      * Installs this model, which includes registering as document
430      * listener on all involved documents and storing global information about
431      * this model. Any conflicting model already present will be
432      * closed.
433      * <p>
434      * If an exception is thrown, the installation failed and
435      * the model is unusable.
436      * </p>
437      *
438      * @throws BadLocationException if some of the positions of this model
439      * were not valid positions on their respective documents
440      */

441     public void forceInstall() throws BadLocationException {
442         if (!install(true))
443             Assert.isTrue(false);
444     }
445
446     /**
447      * Installs this model, which includes registering as document
448      * listener on all involved documents and storing global information about
449      * this model. If there is another model installed on the
450      * document(s) targeted by the receiver that conflicts with it, installation
451      * may fail.
452      * <p>
453      * The return value states whether installation was
454      * successful; if not, the model is not installed and will not work.
455      * </p>
456      *
457      * @return <code>true</code> if installation was successful,
458      * <code>false</code> otherwise
459      * @throws BadLocationException if some of the positions of this model
460      * were not valid positions on their respective documents
461      */

462     public boolean tryInstall() throws BadLocationException {
463         return install(false);
464     }
465
466     /**
467      * Installs this model, which includes registering as document
468      * listener on all involved documents and storing global information about
469      * this model. The return value states whether installation was
470      * successful; if not, the model is not installed and will not work.
471      * The return value can only then become <code>false</code> if
472      * <code>force</code> was set to <code>false</code> as well.
473      *
474      * @param force if <code>true</code>, any other model that cannot
475      * coexist with this one is canceled; if <code>false</code>,
476      * install will fail when conflicts occur and return false
477      * @return <code>true</code> if installation was successful,
478      * <code>false</code> otherwise
479      * @throws BadLocationException if some of the positions of this model
480      * were not valid positions on their respective documents
481      */

482     private boolean install(boolean force) throws BadLocationException {
483         if (fIsSealed)
484             throw new IllegalStateException JavaDoc("model is already installed"); //$NON-NLS-1$
485
enforceNotEmpty();
486
487         IDocument[] documents= getDocuments();
488         LinkedModeManager manager= LinkedModeManager.getLinkedManager(documents, force);
489         // if we force creation, we require a valid manager
490
Assert.isTrue(!(force && manager == null));
491         if (manager == null)
492             return false;
493
494         if (!manager.nestEnvironment(this, force))
495             if (force)
496                 Assert.isTrue(false);
497             else
498                 return false;
499
500         // we set up successfully. After this point, exit has to be called to
501
// remove registered listeners...
502
fIsSealed= true;
503         if (fParentEnvironment != null)
504             fParentEnvironment.suspend();
505
506         // register positions
507
try {
508             for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
509                 LinkedPositionGroup group= (LinkedPositionGroup) it.next();
510                 group.register(this);
511             }
512             return true;
513         } catch (BadLocationException e){
514             // if we fail to add, make sure to release all listeners again
515
exit(ILinkedModeListener.NONE);
516             throw e;
517         }
518     }
519
520     /**
521      * Asserts that there is at least one linked position in this linked mode
522      * model, throws an IllegalStateException otherwise.
523      */

524     private void enforceNotEmpty() {
525         boolean hasPosition= false;
526         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); )
527             if (!((LinkedPositionGroup) it.next()).isEmpty()) {
528                 hasPosition= true;
529                 break;
530             }
531         if (!hasPosition)
532             throw new IllegalStateException JavaDoc("must specify at least one linked position"); //$NON-NLS-1$
533

534     }
535
536     /**
537      * Collects all the documents that contained positions are set upon.
538      * @return the set of documents affected by this model
539      */

540     private IDocument[] getDocuments() {
541         Set JavaDoc docs= new HashSet JavaDoc();
542         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
543             LinkedPositionGroup group= (LinkedPositionGroup) it.next();
544             docs.addAll(Arrays.asList(group.getDocuments()));
545         }
546         return (IDocument[]) docs.toArray(new IDocument[docs.size()]);
547     }
548
549     /**
550      * Returns whether the receiver can be nested into the given <code>parent</code>
551      * model. If yes, the parent model and its position that the receiver
552      * fits in are remembered.
553      *
554      * @param parent the parent model candidate
555      * @return <code>true</code> if the receiver can be nested into <code>parent</code>, <code>false</code> otherwise
556      */

557     boolean canNestInto(LinkedModeModel parent) {
558         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
559             LinkedPositionGroup group= (LinkedPositionGroup) it.next();
560             if (!enforceNestability(group, parent)) {
561                 fParentPosition= null;
562                 return false;
563             }
564         }
565
566         Assert.isNotNull(fParentPosition);
567         fParentEnvironment= parent;
568         return true;
569     }
570
571     /**
572      * Called by nested models when a group is added to them. All
573      * positions in all groups of a nested model have to fit inside a
574      * single position in the parent model.
575      *
576      * @param group the group of the nested model to be adopted.
577      * @param model the model to check against
578      * @return <code>false</code> if it failed to enforce nestability
579      */

580     private boolean enforceNestability(LinkedPositionGroup group, LinkedModeModel model) {
581         Assert.isNotNull(model);
582         Assert.isNotNull(group);
583
584         try {
585             for (Iterator JavaDoc it= model.fGroups.iterator(); it.hasNext(); ) {
586                 LinkedPositionGroup pg= (LinkedPositionGroup) it.next();
587                 LinkedPosition pos;
588                 pos= pg.adopt(group);
589                 if (pos != null && fParentPosition != null && fParentPosition != pos)
590                     return false; // group does not fit into one parent position, which is illegal
591
else if (fParentPosition == null && pos != null)
592                     fParentPosition= pos;
593             }
594         } catch (BadLocationException e) {
595             return false;
596         }
597
598         // group must fit into exactly one of the parent's positions
599
return fParentPosition != null;
600     }
601
602     /**
603      * Returns whether this model is nested.
604      *
605      * <p>
606      * This method is part of the private protocol between
607      * <code>LinkedModeUI</code> and <code>LinkedModeModel</code>.
608      * </p>
609      *
610      * @return <code>true</code> if this model is nested,
611      * <code>false</code> otherwise
612      */

613     public boolean isNested() {
614         return fParentEnvironment != null;
615     }
616
617     /**
618      * Returns the positions in this model that have a tab stop, in the
619      * order they were added.
620      *
621      * <p>
622      * This method is part of the private protocol between
623      * <code>LinkedModeUI</code> and <code>LinkedModeModel</code>.
624      * </p>
625      *
626      * @return the positions in this model that have a tab stop, in the
627      * order they were added
628      */

629     public List JavaDoc getTabStopSequence() {
630         return fPositionSequence;
631     }
632
633     /**
634      * Adds <code>listener</code> to the set of listeners that are informed
635      * upon state changes.
636      *
637      * @param listener the new listener
638      */

639     public void addLinkingListener(ILinkedModeListener listener) {
640         Assert.isNotNull(listener);
641         if (!fListeners.contains(listener))
642             fListeners.add(listener);
643     }
644
645     /**
646      * Removes <code>listener</code> from the set of listeners that are
647      * informed upon state changes.
648      *
649      * @param listener the new listener
650      */

651     public void removeLinkingListener(ILinkedModeListener listener) {
652         fListeners.remove(listener);
653     }
654
655     /**
656      * Finds the position in this model that is closest after
657      * <code>toFind</code>. <code>toFind</code> needs not be a position in
658      * this model and serves merely as an offset.
659      *
660      * <p>
661      * This method part of the private protocol between
662      * <code>LinkedModeUI</code> and <code>LinkedModeModel</code>.
663      * </p>
664      *
665      * @param toFind the position to search from
666      * @return the closest position in the same document as <code>toFind</code>
667      * after the offset of <code>toFind</code>, or <code>null</code>
668      */

669     public LinkedPosition findPosition(LinkedPosition toFind) {
670         LinkedPosition position= null;
671         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
672             LinkedPositionGroup group= (LinkedPositionGroup) it.next();
673             position= group.getPosition(toFind);
674             if (position != null)
675                 break;
676         }
677         return position;
678     }
679
680     /**
681      * Registers a <code>LinkedPosition</code> with this model. Called
682      * by <code>PositionGroup</code>.
683      *
684      * @param position the position to register
685      * @throws BadLocationException if the position cannot be added to its
686      * document
687      */

688     void register(LinkedPosition position) throws BadLocationException {
689         Assert.isNotNull(position);
690
691         IDocument document= position.getDocument();
692         manageDocument(document);
693         try {
694             document.addPosition(getCategory(), position);
695         } catch (BadPositionCategoryException e) {
696             // won't happen as the category has been added by manageDocument()
697
Assert.isTrue(false);
698         }
699         int seqNr= position.getSequenceNumber();
700         if (seqNr != LinkedPositionGroup.NO_STOP) {
701             fPositionSequence.add(position);
702         }
703     }
704
705     /**
706      * Suspends this model.
707      */

708     private void suspend() {
709         List JavaDoc l= new ArrayList JavaDoc(fListeners);
710         for (Iterator JavaDoc it= l.iterator(); it.hasNext(); ) {
711             ILinkedModeListener listener= (ILinkedModeListener) it.next();
712             listener.suspend(this);
713         }
714     }
715
716     /**
717      * Resumes this model. <code>flags</code> can be <code>NONE</code>
718      * or <code>SELECT</code>.
719      *
720      * @param flags <code>NONE</code> or <code>SELECT</code>
721      */

722     private void resume(int flags) {
723         List JavaDoc l= new ArrayList JavaDoc(fListeners);
724         for (Iterator JavaDoc it= l.iterator(); it.hasNext(); ) {
725             ILinkedModeListener listener= (ILinkedModeListener) it.next();
726             listener.resume(this, flags);
727         }
728     }
729
730     /**
731      * Returns whether an offset is contained by any position in this
732      * model.
733      *
734      * @param offset the offset to check
735      * @return <code>true</code> if <code>offset</code> is included by any
736      * position (see {@link LinkedPosition#includes(int)}) in this
737      * model, <code>false</code> otherwise
738      */

739     public boolean anyPositionContains(int offset) {
740         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
741             LinkedPositionGroup group= (LinkedPositionGroup) it.next();
742             if (group.contains(offset))
743                 // take the first hit - exclusion is guaranteed by enforcing
744
// disjointness when adding positions
745
return true;
746         }
747         return false;
748     }
749
750     /**
751      * Returns the linked position group that contains <code>position</code>,
752      * or <code>null</code> if <code>position</code> is not contained in any
753      * group within this model. Group containment is tested by calling
754      * <code>group.contains(position)</code> for every <code>group</code> in
755      * this model.
756      *
757      * <p>
758      * This method part of the private protocol between
759      * <code>LinkedModeUI</code> and <code>LinkedModeModel</code>.
760      * </p>
761      *
762      * @param position the position the group of which is requested
763      * @return the first group in this model for which
764      * <code>group.contains(position)</code> returns <code>true</code>,
765      * or <code>null</code> if no group contains <code>position</code>
766      */

767     public LinkedPositionGroup getGroupForPosition(Position position) {
768         for (Iterator JavaDoc it= fGroups.iterator(); it.hasNext(); ) {
769             LinkedPositionGroup group= (LinkedPositionGroup) it.next();
770             if (group.contains(position))
771                 return group;
772         }
773         return null;
774     }
775 }
776
Popular Tags