KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > editor > fold > FoldHierarchy


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.api.editor.fold;
21
22 import java.util.Collection JavaDoc;
23 import java.util.Collections JavaDoc;
24 import javax.swing.event.DocumentEvent JavaDoc;
25 import javax.swing.text.BadLocationException JavaDoc;
26 import javax.swing.text.Document JavaDoc;
27 import javax.swing.text.JTextComponent JavaDoc;
28 import org.netbeans.modules.editor.fold.ApiPackageAccessor;
29 import org.netbeans.modules.editor.fold.FoldHierarchyExecution;
30 import org.netbeans.modules.editor.fold.FoldOperationImpl;
31
32 /**
33  * Hierarchy of the folds for a single text component represents
34  * a model of the code-folding.
35  *
36  * <br>
37  * It is the main entry point into the Code Folding API.
38  * <br>
39  * Its instance can be obtained by {@link #get(javax.swing.text.JTextComponent)}.
40  * <br>
41  * The hierarhcy mainly provides access to the root fold
42  * by {@link #getRootFold()}
43  * and allows to expand/collapse the folds
44  * and listen for fold events describing folds structure changes
45  * and state changes of any of the folds in the hierarchy.
46  *
47  * <p>
48  * Hierarchy is logically bound to view
49  * i.e. {@link javax.swing.text.JTextComponent}
50  * instead of the document model because
51  * if there would be two views over the same document
52  * then a particular fold can be collapsed in one view
53  * but uncollapsed in another.
54  * <br>
55  * It's up to the concrete fold implementations to possibly share
56  * some common information even on document model level
57  * e.g. java-related folds in multiple views over
58  * a single java source document can share
59  * the document-level parsing information.
60  * <br>
61  * On the other hand user-defined folds (e.g. by collapsing caret selection)
62  * will only be held for the component in which they were created.
63  *
64  * <p>
65  * Only one thread at the time can access the code folding hierarchy.
66  * Prior working with the hierarchy a document-level lock
67  * must be obtained first followed by call to {@link #render(Runnable)}
68  * (or {@link #lock()} for advanced uses) which ensure that the hierarchy
69  * gets locked exclusively.
70  * <br>
71  * The document lock can be either readlock
72  * e.g. by using {@link javax.swing.text.Document#render(Runnable)}
73  * or writelock
74  * e.g. when in {@link javax.swing.event.DocumentListener})
75  * and must be obtained on component's document
76  * i.e. {@link javax.swing.text.JTextComponent#getDocument()}
77  * should be used.
78  *
79  * <p>
80  * The whole fold hierarchy related code expects that the document
81  * instances of the text component will subclass
82  * <code>javax.swing.text.AbstractDocument</code>.
83  *
84  * @author Miloslav Metelka
85  * @version 1.00
86  */

87
88 public final class FoldHierarchy {
89
90     /**
91      * Fold type for the root fold.
92      */

93     public static final FoldType ROOT_FOLD_TYPE = new FoldType("root-fold"); // NOI18N
94

95     private static boolean apiPackageAccessorRegistered;
96
97     static {
98         ensureApiAccessorRegistered();
99     }
100     
101     private static void ensureApiAccessorRegistered() {
102         if (!apiPackageAccessorRegistered) {
103             apiPackageAccessorRegistered = true;
104             ApiPackageAccessor.register(new ApiPackageAccessorImpl());
105         }
106     }
107     
108     /**
109      * Execution carries out most of the fold hierarchy's functionality.
110      */

111     private FoldHierarchyExecution execution;
112     
113     /**
114      * Get the fold hierarchy for the given component. If the hierarchy
115      * does not exist yet it will get created.
116      * <br>
117      * The hierarchy will exist for the entire lifetime of the component.
118      * It is maintained as a client property of it.
119      *
120      * @return non-null fold hierarchy for the component.
121      */

122     public static synchronized FoldHierarchy get(JTextComponent JavaDoc component) {
123         return FoldHierarchyExecution.getOrCreateFoldHierarchy(component);
124     }
125     
126     /** Only instances created internally are allowed. */
127     private FoldHierarchy(FoldHierarchyExecution execution) {
128         // Synced under FoldHierarchy.class lock
129
this.execution = execution;
130     }
131
132     /**
133      * Execute the given runnable over the exclusively locked hierarchy.
134      * <br>
135      * Prior using this method the document must be locked.
136      * The document lock can be either readlock
137      * e.g. by using {@link javax.swing.text.Document#render(Runnable)}
138      * or writelock
139      * e.g. when in {@link javax.swing.event.DocumentListener})
140      * and must be obtained on component's document
141      * i.e. {@link javax.swing.text.JTextComponent#getDocument()}
142      * should be used.
143      *
144      * @param r the runnable to be executed.
145      */

146     public void render(Runnable JavaDoc r) {
147         lock();
148         try {
149             r.run();
150         } finally {
151             unlock();
152         }
153     }
154     
155     /**
156      * Lock the hierarchy for exclusive use. This method must only
157      * be used together with {@link #unlock()} in <code>try..finally</code> block.
158      * <br>
159      * Prior using this method the document must be locked.
160      * The document lock can be either readlock
161      * e.g. by using {@link javax.swing.text.Document#render(Runnable)}
162      * or writelock
163      * e.g. when in {@link javax.swing.event.DocumentListener})
164      * and must be obtained on component's document
165      * i.e. {@link javax.swing.text.JTextComponent#getDocument()}
166      * should be used.
167      *
168      * <p>
169      * <font color="red">
170      * <b>Note:</b> The clients using this method must ensure that
171      * they <b>always</b> use this method in the following pattern:<pre>
172      *
173      * lock();
174      * try {
175      * ...
176      * } finally {
177      * unlock();
178      * }
179      * </pre>
180      * </font>
181      *
182      * @see #render(Runnable)
183      */

184     public void lock() {
185         execution.lock();
186     }
187
188     /**
189      * Unlock the hierarchy from exclusive use. This method must only
190      * be used together with {@link #lock()} in <code>try..finally</code> block.
191      */

192     public void unlock() {
193         execution.unlock();
194     }
195
196     /**
197      * Collapse the given fold.
198      * <br>
199      * Nothing is done if the fold is already collapsed.
200      *
201      * <p>
202      * <b>Note:</b> The hierarchy must be locked prior using of this method.
203      *
204      * @param f fold to be collapsed.
205      */

206     public void collapse(Fold f) {
207         collapse(Collections.singletonList(f));
208     }
209     
210     /**
211      * Collapse all the folds contained in the given collection.
212      *
213      * <p>
214      * <b>Note:</b> The hierarchy must be locked prior using of this method.
215      *
216      * @param c collection of the {@link Fold}s to be collapsed. The folds
217      * must be present in this hierarchy.
218      */

219     public void collapse(Collection JavaDoc c) {
220         execution.collapse(c);
221     }
222     
223     /**
224      * Expand the given fold.
225      * <br>
226      * Nothing is done if the fold is already expanded.
227      *
228      * <p>
229      * <b>Note:</b> The hierarchy must be locked prior using of this method.
230      *
231      * @param f fold to be expanded.
232      */

233     public void expand(Fold f) {
234         expand(Collections.singletonList(f));
235     }
236     
237     /**
238      * Expand all the folds contained in the given collection.
239      *
240      * <p>
241      * <b>Note:</b> The hierarchy must be locked prior using of this method.
242      *
243      * @param c collection of the {@link Fold}s to be collapsed. The folds
244      * must be present in this hierarchy.
245      */

246     public void expand(Collection JavaDoc c) {
247         execution.expand(c);
248     }
249     
250     /**
251      * Collapse the given fold if it's expanded and expand it if it's
252      * collapsed.
253      *
254      * <p>
255      * <b>Note:</b> The hierarchy must be locked prior using of this method.
256      *
257      * @param f fold which state should be toggled.
258      */

259     public void toggle(Fold f) {
260         if (f.isCollapsed()) {
261             expand(f);
262         } else { // expanded
263
collapse(f);
264         }
265     }
266
267     /**
268      * Get the text component for which this fold hierarchy was created.
269      *
270      * @return non-null text component for which this fold hierarchy was created.
271      */

272     public JTextComponent JavaDoc getComponent() {
273         return execution.getComponent();
274     }
275
276     /**
277      * Get the root fold of this hierarchy.
278      *
279      * @return root fold of this hierarchy.
280      * The root fold covers the whole document and is uncollapsable.
281      */

282     public Fold getRootFold() {
283         return execution.getRootFold();
284     }
285     
286     /**
287      * Add listener for changes done in the hierarchy.
288      *
289      * @param l non-null listener to be added.
290      */

291     public void addFoldHierarchyListener(FoldHierarchyListener l) {
292         execution.addFoldHierarchyListener(l);
293     }
294     
295     /**
296      * Remove previously added listener for changes done in the hierarchy.
297      *
298      * @param l non-null listener to be removed.
299      */

300     public void removeFoldHierarchyListener(FoldHierarchyListener l) {
301         execution.removeFoldHierarchyListener(l);
302     }
303
304     /**
305      * Get a string description of the hierarchy for debugging purposes.
306      * <br>
307      * Like all other methods this one can only be used under locking
308      * conditions for the hierarchy.
309      */

310     public String JavaDoc toString() {
311         return execution.toString();
312     }
313
314     /**
315      * Implementation of the API package accessor allows the implementation
316      * to access certain package-private methods from the api classes.
317      */

318     private static final class ApiPackageAccessorImpl extends ApiPackageAccessor {
319         
320         public FoldHierarchy createFoldHierarchy(FoldHierarchyExecution execution) {
321             return new FoldHierarchy(execution);
322         }
323         
324         public Fold createFold(FoldOperationImpl operation,
325         FoldType type, String JavaDoc description, boolean collapsed,
326         Document JavaDoc doc, int startOffset, int endOffset,
327         int startGuardedLength, int endGuardedLength,
328         Object JavaDoc extraInfo)
329         throws BadLocationException JavaDoc {
330             return new Fold(operation, type, description, collapsed,
331                 doc, startOffset, endOffset,
332                 startGuardedLength, endGuardedLength,
333                 extraInfo
334             );
335         }
336         
337         public FoldHierarchyEvent createFoldHierarchyEvent(FoldHierarchy source,
338         Fold[] removedFolds, Fold[] addedFolds, FoldStateChange[] foldStateChanges,
339         int affectedStartOffset, int affectedEndOffset) {
340             return new FoldHierarchyEvent(source, removedFolds, addedFolds,
341                 foldStateChanges, affectedStartOffset, affectedEndOffset);
342         }
343         
344         public FoldStateChange createFoldStateChange(Fold fold) {
345             return new FoldStateChange(fold);
346         }
347         
348         public void foldSetParent(Fold fold, Fold parent) {
349             fold.setParent(parent);
350         }
351
352         public void foldExtractToChildren(Fold fold, int index, int length, Fold targetFold) {
353             fold.extractToChildren(index, length, targetFold);
354         }
355
356         public Fold foldReplaceByChildren(Fold fold, int index) {
357             return fold.replaceByChildren(index);
358         }
359
360         public void foldSetCollapsed(Fold fold, boolean collapsed) {
361             fold.setCollapsed(collapsed);
362         }
363         
364         public void foldSetDescription(Fold fold, String JavaDoc description) {
365             fold.setDescription(description);
366         }
367         
368         public void foldSetStartOffset(Fold fold, Document JavaDoc doc, int startOffset)
369         throws BadLocationException JavaDoc {
370             fold.setStartOffset(doc, startOffset);
371         }
372         
373         public void foldSetEndOffset(Fold fold, Document JavaDoc doc, int endOffset)
374         throws BadLocationException JavaDoc {
375             fold.setEndOffset(doc, endOffset);
376         }
377         
378         public boolean foldIsStartDamaged(Fold fold) {
379             return fold.isStartDamaged();
380         }
381
382         public boolean foldIsEndDamaged(Fold fold) {
383             return fold.isEndDamaged();
384         }
385
386         public boolean foldIsExpandNecessary(Fold fold) {
387             return fold.isExpandNecessary();
388         }
389
390         public void foldInsertUpdate(Fold fold, DocumentEvent JavaDoc evt) {
391             fold.insertUpdate(evt);
392         }
393     
394         public void foldRemoveUpdate(Fold fold, DocumentEvent JavaDoc evt) {
395             fold.removeUpdate(evt);
396         }
397
398         public FoldOperationImpl foldGetOperation(Fold fold) {
399             return fold.getOperation();
400         }
401     
402         public int foldGetRawIndex(Fold fold) {
403             return fold.getRawIndex();
404         }
405         
406         public void foldSetRawIndex(Fold fold, int rawIndex) {
407             fold.setRawIndex(rawIndex);
408         }
409         
410         public void foldUpdateRawIndex(Fold fold, int rawIndexDelta) {
411             fold.updateRawIndex(rawIndexDelta);
412         }
413         
414         public Object JavaDoc foldGetExtraInfo(Fold fold) {
415             return fold.getExtraInfo();
416         }
417         
418         public void foldStateChangeCollapsedChanged(FoldStateChange fsc) {
419             fsc.collapsedChanged();
420         }
421         
422         public void foldStateChangeDescriptionChanged(FoldStateChange fsc) {
423             fsc.descriptionChanged();
424         }
425         
426         public void foldStateChangeStartOffsetChanged(FoldStateChange fsc,
427         int originalStartOffset) {
428             fsc.startOffsetChanged(originalStartOffset);
429         }
430         
431         public void foldStateChangeEndOffsetChanged(FoldStateChange fsc,
432         int originalEndOffset) {
433             fsc.endOffsetChanged(originalEndOffset);
434         }
435         
436     }
437
438 }
439
Popular Tags