KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > editor > fold > FoldUtilitiesImpl


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.modules.editor.fold;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Comparator JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import javax.swing.text.AbstractDocument JavaDoc;
29 import org.netbeans.api.editor.fold.Fold;
30 import org.netbeans.api.editor.fold.FoldHierarchy;
31 import org.netbeans.api.editor.fold.FoldHierarchyEvent;
32 import org.netbeans.api.editor.fold.FoldStateChange;
33 import org.netbeans.api.editor.fold.FoldUtilities;
34
35 /**
36  * Implementations of methods from {@link org.netbeans.api.editor.fold.FoldUtilities}.
37  *
38  * @author Miloslav Metelka
39  * @version 1.00
40  */

41
42 public final class FoldUtilitiesImpl {
43     
44     private FoldUtilitiesImpl() {
45         // No instances
46
}
47     
48     public static void collapseOrExpand(FoldHierarchy hierarchy, Collection JavaDoc foldTypes,
49     boolean collapse) {
50
51         AbstractDocument JavaDoc adoc = (AbstractDocument JavaDoc)hierarchy.getComponent().getDocument();
52         adoc.readLock();
53         try {
54             hierarchy.lock();
55             try {
56                 List JavaDoc foldList = findRecursive(null,
57                     hierarchy.getRootFold(), foldTypes);
58                 if (collapse) {
59                     hierarchy.collapse(foldList);
60                 } else {
61                     hierarchy.expand(foldList);
62                 }
63             } finally {
64                 hierarchy.unlock();
65             }
66         } finally {
67             adoc.readUnlock();
68         }
69     }
70
71     public static int findFoldStartIndex(Fold fold, int offset, boolean first) {
72         int foldCount = fold.getFoldCount();
73         int low = 0;
74         int high = foldCount - 1;
75         
76         while (low <= high) {
77             int mid = (low + high) / 2;
78             Fold midFold = fold.getFold(mid);
79             int midFoldStartOffset = midFold.getStartOffset();
80             
81             if (midFoldStartOffset < offset) {
82                 low = mid + 1;
83             } else if (midFoldStartOffset > offset) {
84                 high = mid - 1;
85             } else {
86                 // fold starting exactly at the given offset found
87
if (first) { // search for first fold
88
mid--;
89                     while (mid >= 0 && fold.getFold(mid).getStartOffset() == offset) {
90                         mid--;
91                     }
92                     mid++;
93                     
94                 } else { // search for last fold
95
mid++;
96                     // Search for fold with startOffset greater than offset
97
while (mid < foldCount && fold.getFold(mid).getStartOffset() == offset) {
98                         mid++;
99                     }
100                     mid--;
101                 }
102                 return mid;
103             }
104         }
105         return high;
106     }
107
108     /**
109      * Find a hint index of where a child fold should be inserted in its parent.
110      *
111      * @param fold fold into which the child fold should be inserted.
112      * @param childStartOffset starting offset of the child to be inserted.
113      * @return hint index at which the child fold should be inserted.
114      * <br>
115      * The client must additionally check whether the end offset
116      * of the preceding child fold does not overlap with the given child fold
117      * and if so then either remove the clashing fold or stop inserting
118      * the child fold.
119      * <br>
120      * The client must also check whether ending offset of the given child fold
121      * does not overlap with the starting offset of the following child fold.
122      */

123     public static int findFoldInsertIndex(Fold fold, int childStartOffset) {
124         return findFoldStartIndex(fold, childStartOffset, false) + 1;
125     }
126
127     public static int findFoldEndIndex(Fold fold, int offset) {
128         int foldCount = fold.getFoldCount();
129         int low = 0;
130         int high = foldCount - 1;
131         
132         while (low <= high) {
133             int mid = (low + high) / 2;
134             Fold midFold = fold.getFold(mid);
135             int midFoldEndOffset = midFold.getEndOffset();
136             
137             if (midFoldEndOffset < offset) {
138                 low = mid + 1;
139             } else if (midFoldEndOffset > offset) {
140                 high = mid - 1;
141             } else {
142                 // fold ending exactly at the given offset found => move to next one above
143
mid++;
144                 while (mid < foldCount && fold.getFold(mid).getEndOffset() <= offset) {
145                     mid++;
146                 }
147                 return mid;
148             }
149         }
150         return low;
151     }
152
153     public static List JavaDoc childrenAsList(Fold fold, int index, int count) {
154         List JavaDoc l = new ArrayList JavaDoc(count);
155         while (--count >= 0) {
156             l.add(fold.getFold(index));
157             index++;
158         }
159         return l;
160     }
161
162     public static List JavaDoc find(Fold fold, Collection JavaDoc foldTypes) {
163         List JavaDoc l = new ArrayList JavaDoc();
164         int foldCount = fold.getFoldCount();
165         for (int i = 0; i < foldCount; i++) {
166             Fold child = fold.getFold(i);
167             if (foldTypes == null || foldTypes.contains(child.getType())) {
168                 l.add(child);
169             }
170         }
171         return l;
172     }
173     
174     public static List JavaDoc findRecursive(List JavaDoc l, Fold fold, Collection JavaDoc foldTypes) {
175         if (l == null) {
176             l = new ArrayList JavaDoc();
177         }
178
179         int foldCount = fold.getFoldCount();
180         for (int i = 0; i < foldCount; i++) {
181             Fold child = fold.getFold(i);
182             if (foldTypes == null || foldTypes.contains(child.getType())) {
183                 l.add(child);
184             }
185             findRecursive(l, child, foldTypes);
186         }
187         return l;
188
189     }
190     
191     /** Returns the fold at the specified offset. Returns null in case of root fold */
192     public static Fold findOffsetFold(FoldHierarchy hierarchy, int offset) {
193         int distance = Integer.MAX_VALUE;
194         Fold rootFold = hierarchy.getRootFold();
195         Fold fold = rootFold;
196         
197         boolean inspectNested = true;
198         while (inspectNested) {
199             int childIndex = findFoldStartIndex(fold, offset, false);
200             if (childIndex >= 0) {
201                 Fold wrapFold = fold.getFold(childIndex);
202                 int startOffset = wrapFold.getStartOffset();
203                 int endOffset = wrapFold.getEndOffset();
204                 // This is not like containsOffset() because of "<= endOffset"
205
if (startOffset <= offset && offset <= endOffset) {
206                     fold = wrapFold;
207                 }else{
208                     inspectNested = false;
209                 }
210             } else { // no children => break
211
inspectNested = false;
212             }
213         }
214         return (fold != rootFold) ? fold : null;
215     }
216     
217     public static Fold findNearestFold(FoldHierarchy hierarchy, int offset, int endOffset) {
218         Fold nearestFold = null;
219         int distance = Integer.MAX_VALUE;
220         Fold fold = hierarchy.getRootFold();
221         
222         boolean inspectNested = true;
223         while (inspectNested) {
224             int childCount = fold.getFoldCount();
225             int childIndex = findFoldEndIndex(fold, offset);
226             if (childIndex < childCount) {
227                 Fold wrapOrAfterFold = fold.getFold(childIndex);
228                 int startOffset = wrapOrAfterFold.getStartOffset();
229                 if (startOffset >= endOffset) { // starts at or after endOffset
230
break;
231                 }
232
233                 Fold afterFold; // fold after the offset
234
if (startOffset < offset) { // starts below offset
235
childIndex++;
236                     afterFold = (childIndex < childCount) ? fold.getFold(childIndex) : null;
237                     // leave inspectNested to be true and prepare fold variable
238
fold = wrapOrAfterFold;
239                     
240                 } else { // starts above offset
241
afterFold = wrapOrAfterFold;
242                     inspectNested = false;
243                 }
244                 
245                 // Check whether the afterFold is the nearest
246
if (afterFold != null) {
247                     int afterFoldDistance = afterFold.getStartOffset() - offset;
248                     if (afterFoldDistance < distance) {
249                         distance = afterFoldDistance;
250                         nearestFold = afterFold;
251                     }
252                 }
253                 
254             } else { // no children => break
255
inspectNested = false;
256             }
257         }
258         
259         return nearestFold;
260     }
261     
262     public static Fold findFirstCollapsedFold(FoldHierarchy hierarchy,
263     int startOffset, int endOffset) {
264         
265         Fold fold = hierarchy.getRootFold();
266         Fold lastFold = null;
267         int lastIndex = 0;
268         while (true) {
269             // Find fold covering the startOffset
270
int index = findFoldEndIndex(fold, startOffset);
271             if (index >= fold.getFoldCount()) {
272                 if (lastFold != null) {
273                     return findCollapsedRec(lastFold, lastIndex + 1, endOffset);
274                 } else { // root level - no satisfying folds
275
return null;
276                 }
277                 
278             } else { // fold index within bounds
279
Fold childFold = fold.getFold(index);
280                 if (childFold.isCollapsed()) { // return it if it's collapsed
281
return childFold;
282                 }
283
284                 if (childFold.getStartOffset() >= startOffset) { // do not nest
285
return findCollapsedRec(fold, index, endOffset);
286                 } else { // need to inspect children
287
lastFold = fold;
288                     lastIndex = index;
289                     fold = childFold;
290                 }
291             }
292         }
293     }
294
295     public static Iterator JavaDoc collapsedFoldIterator(FoldHierarchy hierarchy, int startOffset, int endOffset) {
296         return new CollapsedFoldIterator(
297             findFirstCollapsedFold(hierarchy, startOffset, endOffset),
298             endOffset
299         );
300     }
301     
302     private static final class CollapsedFoldIterator implements Iterator JavaDoc {
303         
304         private Fold nextFold;
305         
306         private int endOffset;
307         
308         public CollapsedFoldIterator(Fold nextFold, int endOffset) {
309             this.nextFold = nextFold;
310             this.endOffset = endOffset;
311         }
312         
313         public boolean hasNext() {
314             return (nextFold != null);
315         }
316         
317         public Object JavaDoc next() {
318             Fold result = nextFold;
319             nextFold = findNextCollapsedFold(nextFold, endOffset);
320             return result;
321         }
322         
323         public void remove() {
324             throw new UnsupportedOperationException JavaDoc();
325         }
326         
327     }
328         
329     public static Fold findNextCollapsedFold(Fold fold, int endOffset) {
330         if (FoldUtilities.isRootFold(fold)) { // start from the begining
331
return findCollapsedRec(fold, 0, endOffset);
332
333         } else { // continue from valid fold
334
Fold parent = fold.getParent();
335             return findCollapsedRec(parent, parent.getFoldIndex(fold) + 1, endOffset);
336         }
337     }
338     
339     private static Fold findCollapsedRec(Fold fold,
340     int startIndex, int endOffset) {
341         return findCollapsedRec(fold, startIndex, endOffset, true);
342     }
343     
344     private static Fold findCollapsedRec(Fold fold,
345     int startIndex, int endOffset, boolean findInUpperLevel) {
346
347         if (fold.getStartOffset() > endOffset) {
348             return null;
349         }
350
351         int foldCount = fold.getFoldCount();
352         while (startIndex < foldCount) {
353             Fold child = fold.getFold(startIndex);
354             if (child.isCollapsed()) {
355                 return child;
356             } else {
357                 Fold maybeCollapsed = findCollapsedRec(child, 0, endOffset, false);
358                 if (maybeCollapsed != null) {
359                     return maybeCollapsed;
360                 }
361             }
362             startIndex++;
363         }
364
365         // No child was found collapsed -> go one level up
366
if (FoldUtilities.isRootFold(fold) || !findInUpperLevel) {
367             return null;
368         } else { // not root fold
369
Fold parent = fold.getParent();
370             return findCollapsedRec(parent, parent.getFoldIndex(fold) + 1, endOffset, true);
371         }
372     }
373     
374     public static String JavaDoc foldToString(Fold fold) {
375         return "[" + fold.getType() + "] " // NOI18N
376
+ (fold.isCollapsed() ? "C" : "E")// NOI18N
377
+ (FoldUtilities.isRootFold(fold) ? "" : Integer.toString(
378                 ApiPackageAccessor.get().foldGetOperation(fold).getPriority()))
379             + " <" + fold.getStartOffset() // NOI18N
380
+ "," + fold.getEndOffset() + ">" // NOI18N
381
+ (FoldUtilities.isRootFold(fold) ? "" : (", desc='" + fold.getDescription() + "'")); // NOI18N
382
}
383     
384     public static void appendSpaces(StringBuffer JavaDoc sb, int spaces) {
385         while (--spaces >= 0) {
386             sb.append(' ');
387         }
388     }
389
390     public static String JavaDoc foldToStringChildren(Fold fold, int indent) {
391         indent += 4;
392         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
393         sb.append(fold);
394         sb.append('\n');
395         int foldCount = fold.getFoldCount();
396         for (int i = 0; i < foldCount; i++) {
397             appendSpaces(sb, indent);
398             sb.append('[');
399             sb.append(i);
400             sb.append("]: "); // NOI18N
401
sb.append(foldToStringChildren(fold.getFold(i), indent));
402         }
403         
404         return sb.toString();
405     }
406     
407     public static String JavaDoc foldHierarchyEventToString(FoldHierarchyEvent evt) {
408         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
409         int removedFoldCount = evt.getRemovedFoldCount();
410         for (int i = 0; i < removedFoldCount; i++) {
411             sb.append("R["); // NOI18N
412
sb.append(i);
413             sb.append("]: "); // NOI18N
414
sb.append(evt.getRemovedFold(i));
415             sb.append('\n');
416         }
417         
418         int addedFoldCount = evt.getAddedFoldCount();
419         for (int i = 0; i < addedFoldCount; i++) {
420             sb.append("A["); // NOI18N
421
sb.append(i);
422             sb.append("]: "); // NOI18N
423
sb.append(evt.getAddedFold(i));
424             sb.append('\n');
425         }
426         
427         int foldStateChangeCount = evt.getFoldStateChangeCount();
428         for (int i = 0; i < foldStateChangeCount; i++) {
429             FoldStateChange change = evt.getFoldStateChange(i);
430             sb.append("SC["); // NOI18N
431
sb.append(i);
432             sb.append("]: "); // NOI18N
433
sb.append(change);
434             sb.append('\n');
435         }
436         if (foldStateChangeCount == 0) {
437             sb.append("No FoldStateChange\n"); // NOI18N
438
}
439         
440         sb.append("affected: <"); // NOI18N
441
sb.append(evt.getAffectedStartOffset());
442         sb.append(","); // NOI18N
443
sb.append(evt.getAffectedEndOffset());
444         sb.append(">\n"); // NOI18N
445

446         return sb.toString();
447     }
448     
449     public static String JavaDoc foldStateChangeToString(FoldStateChange change) {
450         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
451         if (change.isCollapsedChanged()) {
452             sb.append("C"); // NOI18N
453
}
454         if (change.isDescriptionChanged()) {
455             sb.append("D"); // NOI18N
456
}
457         if (change.isEndOffsetChanged()) {
458             sb.append("E"); // NOI18N
459
}
460         sb.append(" fold="); // NOI18N
461
sb.append(change.getFold());
462         return sb.toString();
463     }
464     
465 }
466
Popular Tags