alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.editor.fold;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import javax.swing.text.AbstractDocument;
import org.netbeans.api.editor.fold.Fold;
import org.netbeans.api.editor.fold.FoldHierarchy;
import org.netbeans.api.editor.fold.FoldHierarchyEvent;
import org.netbeans.api.editor.fold.FoldStateChange;
import org.netbeans.api.editor.fold.FoldUtilities;

/**
 * Implementations of methods from {@link org.netbeans.api.editor.fold.FoldUtilities}.
 *
 * @author Miloslav Metelka
 * @version 1.00
 */

public final class FoldUtilitiesImpl {
    
    private FoldUtilitiesImpl() {
        // No instances
    }
    
    public static void collapseOrExpand(FoldHierarchy hierarchy, Collection foldTypes,
    boolean collapse) {

        AbstractDocument adoc = (AbstractDocument)hierarchy.getComponent().getDocument();
        adoc.readLock();
        try {
            hierarchy.lock();
            try {
                List foldList = findRecursive(null,
                    hierarchy.getRootFold(), foldTypes);
                if (collapse) {
                    hierarchy.collapse(foldList);
                } else {
                    hierarchy.expand(foldList);
                }
            } finally {
                hierarchy.unlock();
            }
        } finally {
            adoc.readUnlock();
        }
    }

    public static int findFoldStartIndex(Fold fold, int offset, boolean first) {
        int foldCount = fold.getFoldCount();
        int low = 0;
        int high = foldCount - 1;
        
        while (low <= high) {
            int mid = (low + high) / 2;
            Fold midFold = fold.getFold(mid);
            int midFoldStartOffset = midFold.getStartOffset();
            
            if (midFoldStartOffset < offset) {
                low = mid + 1;
            } else if (midFoldStartOffset > offset) {
                high = mid - 1;
            } else {
                // fold starting exactly at the given offset found
                if (first) { // search for first fold
                    mid--;
                    while (mid >= 0 && fold.getFold(mid).getStartOffset() == offset) {
                        mid--;
                    }
                    mid++;
                    
                } else { // search for last fold
                    mid++;
                    // Search for fold with startOffset greater than offset
                    while (mid < foldCount && fold.getFold(mid).getStartOffset() == offset) {
                        mid++;
                    }
                    mid--;
                }
                return mid;
            }
        }
        return high;
    }

    /**
     * Find a hint index of where a child fold should be inserted in its parent.
     *
     * @param fold fold into which the child fold should be inserted.
     * @param childStartOffset starting offset of the child to be inserted.
     * @return hint index at which the child fold should be inserted.
     *  
* The client must additionally check whether the end offset * of the preceding child fold does not overlap with the given child fold * and if so then either remove the clashing fold or stop inserting * the child fold. *
* The client must also check whether ending offset of the given child fold * does not overlap with the starting offset of the following child fold. */ public static int findFoldInsertIndex(Fold fold, int childStartOffset) { return findFoldStartIndex(fold, childStartOffset, false) + 1; } public static int findFoldEndIndex(Fold fold, int offset) { int foldCount = fold.getFoldCount(); int low = 0; int high = foldCount - 1; while (low <= high) { int mid = (low + high) / 2; Fold midFold = fold.getFold(mid); int midFoldEndOffset = midFold.getEndOffset(); if (midFoldEndOffset < offset) { low = mid + 1; } else if (midFoldEndOffset > offset) { high = mid - 1; } else { // fold ending exactly at the given offset found => move to next one above mid++; while (mid < foldCount && fold.getFold(mid).getEndOffset() <= offset) { mid++; } return mid; } } return low; } public static List childrenAsList(Fold fold, int index, int count) { List l = new ArrayList(count); while (--count >= 0) { l.add(fold.getFold(index)); index++; } return l; } public static List find(Fold fold, Collection foldTypes) { List l = new ArrayList(); int foldCount = fold.getFoldCount(); for (int i = 0; i < foldCount; i++) { Fold child = fold.getFold(i); if (foldTypes == null || foldTypes.contains(child.getType())) { l.add(child); } } return l; } public static List findRecursive(List l, Fold fold, Collection foldTypes) { if (l == null) { l = new ArrayList(); } int foldCount = fold.getFoldCount(); for (int i = 0; i < foldCount; i++) { Fold child = fold.getFold(i); if (foldTypes == null || foldTypes.contains(child.getType())) { l.add(child); } findRecursive(l, child, foldTypes); } return l; } /** Returns the fold at the specified offset. Returns null in case of root fold */ public static Fold findOffsetFold(FoldHierarchy hierarchy, int offset) { int distance = Integer.MAX_VALUE; Fold rootFold = hierarchy.getRootFold(); Fold fold = rootFold; boolean inspectNested = true; while (inspectNested) { int childIndex = findFoldStartIndex(fold, offset, false); if (childIndex >= 0) { Fold wrapFold = fold.getFold(childIndex); int startOffset = wrapFold.getStartOffset(); int endOffset = wrapFold.getEndOffset(); // This is not like containsOffset() because of "<= endOffset" if (startOffset <= offset && offset <= endOffset) { fold = wrapFold; }else{ inspectNested = false; } } else { // no children => break inspectNested = false; } } return (fold != rootFold) ? fold : null; } public static Fold findNearestFold(FoldHierarchy hierarchy, int offset, int endOffset) { Fold nearestFold = null; int distance = Integer.MAX_VALUE; Fold fold = hierarchy.getRootFold(); boolean inspectNested = true; while (inspectNested) { int childCount = fold.getFoldCount(); int childIndex = findFoldEndIndex(fold, offset); if (childIndex < childCount) { Fold wrapOrAfterFold = fold.getFold(childIndex); int startOffset = wrapOrAfterFold.getStartOffset(); if (startOffset >= endOffset) { // starts at or after endOffset break; } Fold afterFold; // fold after the offset if (startOffset < offset) { // starts below offset childIndex++; afterFold = (childIndex < childCount) ? fold.getFold(childIndex) : null; // leave inspectNested to be true and prepare fold variable fold = wrapOrAfterFold; } else { // starts above offset afterFold = wrapOrAfterFold; inspectNested = false; } // Check whether the afterFold is the nearest if (afterFold != null) { int afterFoldDistance = afterFold.getStartOffset() - offset; if (afterFoldDistance < distance) { distance = afterFoldDistance; nearestFold = afterFold; } } } else { // no children => break inspectNested = false; } } return nearestFold; } public static Fold findFirstCollapsedFold(FoldHierarchy hierarchy, int startOffset, int endOffset) { Fold fold = hierarchy.getRootFold(); Fold lastFold = null; int lastIndex = 0; while (true) { // Find fold covering the startOffset int index = findFoldEndIndex(fold, startOffset); if (index >= fold.getFoldCount()) { if (lastFold != null) { return findCollapsedRec(lastFold, lastIndex + 1, endOffset); } else { // root level - no satisfying folds return null; } } else { // fold index within bounds Fold childFold = fold.getFold(index); if (childFold.isCollapsed()) { // return it if it's collapsed return childFold; } if (childFold.getStartOffset() >= startOffset) { // do not nest return findCollapsedRec(fold, index, endOffset); } else { // need to inspect children lastFold = fold; lastIndex = index; fold = childFold; } } } } public static Iterator collapsedFoldIterator(FoldHierarchy hierarchy, int startOffset, int endOffset) { return new CollapsedFoldIterator( findFirstCollapsedFold(hierarchy, startOffset, endOffset), endOffset ); } private static final class CollapsedFoldIterator implements Iterator { private Fold nextFold; private int endOffset; public CollapsedFoldIterator(Fold nextFold, int endOffset) { this.nextFold = nextFold; this.endOffset = endOffset; } public boolean hasNext() { return (nextFold != null); } public Object next() { Fold result = nextFold; nextFold = findNextCollapsedFold(nextFold, endOffset); return result; } public void remove() { throw new UnsupportedOperationException(); } } public static Fold findNextCollapsedFold(Fold fold, int endOffset) { if (FoldUtilities.isRootFold(fold)) { // start from the begining return findCollapsedRec(fold, 0, endOffset); } else { // continue from valid fold Fold parent = fold.getParent(); return findCollapsedRec(parent, parent.getFoldIndex(fold) + 1, endOffset); } } private static Fold findCollapsedRec(Fold fold, int startIndex, int endOffset) { return findCollapsedRec(fold, startIndex, endOffset, true); } private static Fold findCollapsedRec(Fold fold, int startIndex, int endOffset, boolean findInUpperLevel) { if (fold.getStartOffset() > endOffset) { return null; } int foldCount = fold.getFoldCount(); while (startIndex < foldCount) { Fold child = fold.getFold(startIndex); if (child.isCollapsed()) { return child; } else { Fold maybeCollapsed = findCollapsedRec(child, 0, endOffset, false); if (maybeCollapsed != null) { return maybeCollapsed; } } startIndex++; } // No child was found collapsed -> go one level up if (FoldUtilities.isRootFold(fold) || !findInUpperLevel) { return null; } else { // not root fold Fold parent = fold.getParent(); return findCollapsedRec(parent, parent.getFoldIndex(fold) + 1, endOffset, true); } } public static String foldToString(Fold fold) { return "[" + fold.getType() + "] " // NOI18N + (fold.isCollapsed() ? "C" : "E")// NOI18N + (FoldUtilities.isRootFold(fold) ? "" : Integer.toString( ApiPackageAccessor.get().foldGetOperation(fold).getPriority())) + " <" + fold.getStartOffset() // NOI18N + "," + fold.getEndOffset() + ">" // NOI18N + (FoldUtilities.isRootFold(fold) ? "" : (", desc='" + fold.getDescription() + "'")); // NOI18N } public static void appendSpaces(StringBuffer sb, int spaces) { while (--spaces >= 0) { sb.append(' '); } } public static String foldToStringChildren(Fold fold, int indent) { indent += 4; StringBuffer sb = new StringBuffer(); sb.append(fold); sb.append('\n'); int foldCount = fold.getFoldCount(); for (int i = 0; i < foldCount; i++) { appendSpaces(sb, indent); sb.append('['); sb.append(i); sb.append("]: "); // NOI18N sb.append(foldToStringChildren(fold.getFold(i), indent)); } return sb.toString(); } public static String foldHierarchyEventToString(FoldHierarchyEvent evt) { StringBuffer sb = new StringBuffer(); int removedFoldCount = evt.getRemovedFoldCount(); for (int i = 0; i < removedFoldCount; i++) { sb.append("R["); // NOI18N sb.append(i); sb.append("]: "); // NOI18N sb.append(evt.getRemovedFold(i)); sb.append('\n'); } int addedFoldCount = evt.getAddedFoldCount(); for (int i = 0; i < addedFoldCount; i++) { sb.append("A["); // NOI18N sb.append(i); sb.append("]: "); // NOI18N sb.append(evt.getAddedFold(i)); sb.append('\n'); } int foldStateChangeCount = evt.getFoldStateChangeCount(); for (int i = 0; i < foldStateChangeCount; i++) { FoldStateChange change = evt.getFoldStateChange(i); sb.append("SC["); // NOI18N sb.append(i); sb.append("]: "); // NOI18N sb.append(change); sb.append('\n'); } if (foldStateChangeCount == 0) { sb.append("No FoldStateChange\n"); // NOI18N } sb.append("affected: <"); // NOI18N sb.append(evt.getAffectedStartOffset()); sb.append(","); // NOI18N sb.append(evt.getAffectedEndOffset()); sb.append(">\n"); // NOI18N return sb.toString(); } public static String foldStateChangeToString(FoldStateChange change) { StringBuffer sb = new StringBuffer(); if (change.isCollapsedChanged()) { sb.append("C"); // NOI18N } if (change.isDescriptionChanged()) { sb.append("D"); // NOI18N } if (change.isEndOffsetChanged()) { sb.append("E"); // NOI18N } sb.append(" fold="); // NOI18N sb.append(change.getFold()); return sb.toString(); } }
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.