1 19 20 package org.netbeans.modules.editor.fold; 21 22 import java.util.ArrayList ; 23 import java.util.Arrays ; 24 import java.util.Collection ; 25 import java.util.Comparator ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import javax.swing.text.AbstractDocument ; 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 41 42 public final class FoldUtilitiesImpl { 43 44 private FoldUtilitiesImpl() { 45 } 47 48 public static void collapseOrExpand(FoldHierarchy hierarchy, Collection foldTypes, 49 boolean collapse) { 50 51 AbstractDocument adoc = (AbstractDocument )hierarchy.getComponent().getDocument(); 52 adoc.readLock(); 53 try { 54 hierarchy.lock(); 55 try { 56 List 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 if (first) { mid--; 89 while (mid >= 0 && fold.getFold(mid).getStartOffset() == offset) { 90 mid--; 91 } 92 mid++; 93 94 } else { mid++; 96 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 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 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 childrenAsList(Fold fold, int index, int count) { 154 List l = new ArrayList (count); 155 while (--count >= 0) { 156 l.add(fold.getFold(index)); 157 index++; 158 } 159 return l; 160 } 161 162 public static List find(Fold fold, Collection foldTypes) { 163 List l = new ArrayList (); 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 findRecursive(List l, Fold fold, Collection foldTypes) { 175 if (l == null) { 176 l = new ArrayList (); 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 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 if (startOffset <= offset && offset <= endOffset) { 206 fold = wrapFold; 207 }else{ 208 inspectNested = false; 209 } 210 } else { 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) { break; 231 } 232 233 Fold afterFold; if (startOffset < offset) { childIndex++; 236 afterFold = (childIndex < childCount) ? fold.getFold(childIndex) : null; 237 fold = wrapOrAfterFold; 239 240 } else { afterFold = wrapOrAfterFold; 242 inspectNested = false; 243 } 244 245 if (afterFold != null) { 247 int afterFoldDistance = afterFold.getStartOffset() - offset; 248 if (afterFoldDistance < distance) { 249 distance = afterFoldDistance; 250 nearestFold = afterFold; 251 } 252 } 253 254 } else { 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 int index = findFoldEndIndex(fold, startOffset); 271 if (index >= fold.getFoldCount()) { 272 if (lastFold != null) { 273 return findCollapsedRec(lastFold, lastIndex + 1, endOffset); 274 } else { return null; 276 } 277 278 } else { Fold childFold = fold.getFold(index); 280 if (childFold.isCollapsed()) { return childFold; 282 } 283 284 if (childFold.getStartOffset() >= startOffset) { return findCollapsedRec(fold, index, endOffset); 286 } else { lastFold = fold; 288 lastIndex = index; 289 fold = childFold; 290 } 291 } 292 } 293 } 294 295 public static Iterator 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 { 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 next() { 318 Fold result = nextFold; 319 nextFold = findNextCollapsedFold(nextFold, endOffset); 320 return result; 321 } 322 323 public void remove() { 324 throw new UnsupportedOperationException (); 325 } 326 327 } 328 329 public static Fold findNextCollapsedFold(Fold fold, int endOffset) { 330 if (FoldUtilities.isRootFold(fold)) { return findCollapsedRec(fold, 0, endOffset); 332 333 } else { 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 if (FoldUtilities.isRootFold(fold) || !findInUpperLevel) { 367 return null; 368 } else { Fold parent = fold.getParent(); 370 return findCollapsedRec(parent, parent.getFoldIndex(fold) + 1, endOffset, true); 371 } 372 } 373 374 public static String foldToString(Fold fold) { 375 return "[" + fold.getType() + "] " + (fold.isCollapsed() ? "C" : "E") + (FoldUtilities.isRootFold(fold) ? "" : Integer.toString( 378 ApiPackageAccessor.get().foldGetOperation(fold).getPriority())) 379 + " <" + fold.getStartOffset() + "," + fold.getEndOffset() + ">" + (FoldUtilities.isRootFold(fold) ? "" : (", desc='" + fold.getDescription() + "'")); } 383 384 public static void appendSpaces(StringBuffer sb, int spaces) { 385 while (--spaces >= 0) { 386 sb.append(' '); 387 } 388 } 389 390 public static String foldToStringChildren(Fold fold, int indent) { 391 indent += 4; 392 StringBuffer sb = new StringBuffer (); 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("]: "); sb.append(foldToStringChildren(fold.getFold(i), indent)); 402 } 403 404 return sb.toString(); 405 } 406 407 public static String foldHierarchyEventToString(FoldHierarchyEvent evt) { 408 StringBuffer sb = new StringBuffer (); 409 int removedFoldCount = evt.getRemovedFoldCount(); 410 for (int i = 0; i < removedFoldCount; i++) { 411 sb.append("R["); sb.append(i); 413 sb.append("]: "); 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["); sb.append(i); 422 sb.append("]: "); 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["); sb.append(i); 432 sb.append("]: "); sb.append(change); 434 sb.append('\n'); 435 } 436 if (foldStateChangeCount == 0) { 437 sb.append("No FoldStateChange\n"); } 439 440 sb.append("affected: <"); sb.append(evt.getAffectedStartOffset()); 442 sb.append(","); sb.append(evt.getAffectedEndOffset()); 444 sb.append(">\n"); 446 return sb.toString(); 447 } 448 449 public static String foldStateChangeToString(FoldStateChange change) { 450 StringBuffer sb = new StringBuffer (); 451 if (change.isCollapsedChanged()) { 452 sb.append("C"); } 454 if (change.isDescriptionChanged()) { 455 sb.append("D"); } 457 if (change.isEndOffsetChanged()) { 458 sb.append("E"); } 460 sb.append(" fold="); sb.append(change.getFold()); 462 return sb.toString(); 463 } 464 465 } 466 | Popular Tags |