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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.netbeans.api.editor.fold.Fold;
import org.netbeans.api.editor.fold.FoldHierarchyEvent;
import org.netbeans.api.editor.fold.FoldHierarchyListener;
import org.netbeans.api.editor.fold.FoldStateChange;
import org.netbeans.api.editor.fold.FoldType;
import org.netbeans.api.editor.fold.FoldUtilities;
import org.netbeans.modules.editor.fold.FoldUtilitiesImpl;
import org.netbeans.spi.editor.fold.FoldHierarchyTransaction;
import org.netbeans.spi.editor.fold.FoldManager;
import org.openide.ErrorManager;

/**
 * Class encapsulating a modification
 * of the code folding hierarchy.
 * 
* It's provided by {@link RootFold#createHierarchyTransaction()}. *
* It can accumulate arbitrary number of changes of various folds. *
* Only one transaction can be active at the time. *
* Once all the modifications are done the transaction must be * committed by {@link #commit()} which creates * a {@link org.netbeans.api.editor.fold.FoldHierarchyEvent} * and fires it to the listeners automatically. *
* Once the transaction is committed no additional * changes can be made to it. *
* There is currently no way to rollback the transaction. * * @author Miloslav Metelka * @version 1.00 */ public final class FoldHierarchyTransactionImpl { private static final boolean debug = Boolean.getBoolean("netbeans.debug.editor.fold"); private static final Fold[] EMPTY_FOLDS = new Fold[0]; private static final FoldStateChange[] EMPTY_FOLD_STATE_CHANGES = new FoldStateChange[0]; private static final int[] EMPTY_INT_ARRAY = new int[0]; private FoldHierarchyTransaction transaction; private boolean committed; private FoldHierarchyExecution execution; /** * Fold inside which the last operation (insert or remove) * was done. */ private Fold lastOperationFold; /** * Index at which the last operation (insert or remove) was done. */ private int lastOperationIndex; /** * Fold that is block in case the inspectOverlap() returns null. *
* This is instance var so that inspectOverlap() can set it. */ private Fold addFoldBlock; /** * List of lists of folds that were unblocked by removing * of a blocked fold indexed by the fold priority. *
* Prior to the commit of the transaction the unblocked * folds are attempted to be reinserted into the hierarchy * starting with folds with the highest priority * going to folds with the lowest priority. */ private List unblockedFoldLists = new ArrayList(4); /** * Maximum priority of the unblocked folds added * since the start of this transaction. */ private int unblockedFoldMaxPriority = -1; /** * Set of folds that were added to the hierarchy * during this transaction. */ private Set addedToHierarchySet; /** * Set of folds that were removed from the hierarchy * during this transaction. */ private Set removedFromHierarchySet; private Map fold2StateChange; private int affectedStartOffset; private int affectedEndOffset; public FoldHierarchyTransactionImpl(FoldHierarchyExecution execution) { this.execution = execution; this.affectedStartOffset = Integer.MAX_VALUE; this.affectedEndOffset = -1; this.transaction = SpiPackageAccessor.get().createFoldHierarchyTransaction(this); } public FoldHierarchyTransaction getTransaction() { return transaction; } /** * Commit this active transaction. *
* The FoldHierarchyEvent will be fired automatically * (if there were any changes done during this transaction). *
* The transaction can only be commited once. */ public void commit() { checkNotCommitted(); /** * Mark the transaction as committed now * to prevent problems in case one of the listeners fails later. */ committed = true; execution.clearActiveTransaction(); if (!isEmpty()) { int size; Fold[] removedFolds; if (removedFromHierarchySet != null && ((size = removedFromHierarchySet.size()) != 0)) { removedFolds = new Fold[size]; removedFromHierarchySet.toArray(removedFolds); } else { removedFolds = EMPTY_FOLDS; } Fold[] addedFolds; if (addedToHierarchySet != null && ((size = addedToHierarchySet.size()) != 0)) { addedFolds = new Fold[size]; addedToHierarchySet.toArray(addedFolds); } else { addedFolds = EMPTY_FOLDS; } FoldStateChange[] stateChanges; if (fold2StateChange != null) { stateChanges = new FoldStateChange[fold2StateChange.size()]; fold2StateChange.values().toArray(stateChanges); } else { // no state changes => use empty array stateChanges = EMPTY_FOLD_STATE_CHANGES; } for (int i = stateChanges.length - 1; i >= 0; i--) { FoldStateChange change = stateChanges[i]; Fold fold = change.getFold(); updateAffectedOffsets(fold); int origOffset = change.getOriginalStartOffset(); if (origOffset != -1) { updateAffectedStartOffset(origOffset); } origOffset = change.getOriginalEndOffset(); if (origOffset != -1) { updateAffectedEndOffset(origOffset); } } execution.createAndFireFoldHierarchyEvent( removedFolds, addedFolds, stateChanges, affectedStartOffset, affectedEndOffset ); } } /** * This method implements the DocumentListener. *
* It is not intended to be called by clients. */ public void insertUpdate(DocumentEvent evt) { // Check whether there was an insert done right // at the original ending offset of the fold // so the fold end offset should be moved back. if (debug) { /*DEBUG*/System.err.println("insertUpdate: offset=" + evt.getOffset() // NOI18N + ", length=" + evt.getLength()); // NOI18N } try { insertCheckEndOffset(execution.getRootFold(), evt); } catch (BadLocationException e) { ErrorManager.getDefault().notify(e); } } private void insertCheckEndOffset(Fold fold, DocumentEvent evt) throws BadLocationException { int insertEndOffset = evt.getOffset() + evt.getLength(); // Find first fold that starts at (or best represents) the insertEndOffset int childIndex = FoldUtilitiesImpl.findFoldStartIndex(fold, insertEndOffset, false); if (childIndex >= 0) { // could be at end of the child fold with the index Fold childFold = fold.getFold(childIndex); // Check whether not in fact searching for previous fold if (childIndex > 0 && childFold.getStartOffset() == insertEndOffset) { childIndex--; childFold = fold.getFold(childIndex); } int childFoldEndOffset = childFold.getEndOffset(); // Check whether the child fold "contains" the insert // i.e. the children of the child must be checked as well if (childFoldEndOffset >= insertEndOffset) { // check children // Must dig into children first to maintain consistency // in case when the last child fold would end right at end offset // of this child. insertCheckEndOffset(childFold, evt); // Inform the fold about insertion ApiPackageAccessor.get().foldInsertUpdate(childFold, evt); if (childFoldEndOffset == insertEndOffset) { // Now correct the end offset to the one before insertion setEndOffset(childFold, evt.getDocument(), evt.getOffset()); } else { // not right at the end of the fold -> check damaged ApiPackageAccessor api = ApiPackageAccessor.get(); if (api.foldIsStartDamaged(childFold) || api.foldIsEndDamaged(childFold)) { execution.remove(childFold, this); removeDamagedNotify(childFold); if (debug) { /*DEBUG*/System.err.println("insertUpdate: removed damaged " // NOI18N + childFold); } } } } } } private FoldOperationImpl getOperation(Fold fold) { return ApiPackageAccessor.get().foldGetOperation(fold); } private FoldManager getManager(Fold fold) { return getOperation(fold).getManager(); } private void setEndOffset(Fold fold, Document doc, int endOffset) throws BadLocationException { int origEndOffset = fold.getEndOffset(); ApiPackageAccessor api = ApiPackageAccessor.get(); api.foldSetEndOffset(fold, doc, endOffset); api.foldStateChangeEndOffsetChanged(getFoldStateChange(fold), origEndOffset); } public void setCollapsed(Fold fold, boolean collapsed) { boolean oldCollapsed = fold.isCollapsed(); if (oldCollapsed != collapsed) { ApiPackageAccessor api = ApiPackageAccessor.get(); api.foldSetCollapsed(fold, collapsed); api.foldStateChangeCollapsedChanged(getFoldStateChange(fold)); } } private void removeDamagedNotify(Fold fold) { getManager(fold).removeDamagedNotify(fold); } private void removeEmptyNotify(Fold fold) { getManager(fold).removeEmptyNotify(fold); } /** * This method implements the DocumentListener. *
* It is not intended to be called by clients. */ public void removeUpdate(DocumentEvent evt) { // Check whether the remove damaged any folds // or made them empty. if (debug) { /*DEBUG*/System.err.println("removeUpdate: offset=" + evt.getOffset()); } removeCheckDamaged(execution.getRootFold(), evt); } private void removeCheckDamaged(Fold fold, DocumentEvent evt) { ApiPackageAccessor api = ApiPackageAccessor.get(); int childIndex = FoldUtilitiesImpl.findFoldStartIndex(fold, evt.getOffset(), true); if (childIndex >= 0) { boolean removed; do { Fold childFold = fold.getFold(childIndex); removed = false; if (FoldUtilities.isEmpty(childFold)) { removeCheckDamaged(childFold, evt); // nest prior removing execution.remove(childFold, this); getManager(childFold).removeEmptyNotify(childFold); removed = true; if (debug) { /*DEBUG*/System.err.println("insertUpdate: removed empty " // NOI18N + childFold); } } else if (api.foldIsStartDamaged(childFold) || api.foldIsEndDamaged(childFold)) { removeCheckDamaged(childFold, evt); // nest prior removing execution.remove(childFold, this); getManager(childFold).removeDamagedNotify(childFold); removed = true; if (debug) { /*DEBUG*/System.err.println("insertUpdate: removed damaged " // NOI18N + childFold); } } else if (childFold.getFoldCount() > 0) { // check children // Some children could be damaged even if this one was not removeCheckDamaged(childFold, evt); } // Check whether the expand is necessary if (!removed) { // only if not removed yet if (childFold.isCollapsed() && api.foldIsExpandNecessary(childFold)) { setCollapsed(childFold , false); } api.foldRemoveUpdate(childFold, evt); } // intentionally do not increase childIndex } while (removed && childIndex < fold.getFoldCount()); } } private boolean isEmpty() { return (fold2StateChange == null || fold2StateChange.size() == 0) && (addedToHierarchySet == null || addedToHierarchySet.size() == 0) && (removedFromHierarchySet == null || removedFromHierarchySet.size() == 0); } public FoldStateChange getFoldStateChange(Fold fold) { if (fold2StateChange == null) { fold2StateChange = new HashMap(); } FoldStateChange change = (FoldStateChange)fold2StateChange.get(fold); if (change == null) { change = ApiPackageAccessor.get().createFoldStateChange(fold); fold2StateChange.put(fold, change); } return change; } /** * Remove the fold either from the hierarchy or from the blocked list. */ void removeFold(Fold fold) { if (debug) { /*DEBUG*/System.err.println("removeFold: " + fold); } Fold parent = fold.getParent(); if (parent != null) { // present in hierarchy int index = parent.getFoldIndex(fold); removeFoldFromHierarchy(parent, index, null); // no block passed here lastOperationFold = parent; lastOperationIndex = index; } else { // not present in hierarchy - must be blocked (or error) if (!execution.isBlocked(fold)) { // not blocked i.e. already removed throw new IllegalStateException("Fold already removed: " + fold); // NOI18N } execution.unmarkBlocked(fold); // If the fold was blocking other folds then unblock them here unblockBlocked(fold); } processUnblocked(); // attempt to reinsert unblocked folds } /** * Remove all present folds in the hierarchy * once the managers are going to be switched. */ void removeAllFolds(Fold[] allBlocked) { // First remove all blocked folds for (int i = allBlocked.length - 1; i >= 0; i--) { removeFold(allBlocked[i]); } removeAllChildrenAndSelf(execution.getRootFold()); } private void removeAllChildrenAndSelf(Fold fold) { int foldCount = fold.getFoldCount(); if (foldCount > 0) { for (int i = foldCount - 1; i >= 0; i--) { removeAllChildrenAndSelf(fold.getFold(i)); } } if (!FoldUtilities.isRootFold(fold)) { removeFold(fold); } } public void changedUpdate(DocumentEvent evt) { // No explicit checking actions upon document change notification } /** * Called by FoldHierarchySpi to attempt to insert * the fold into hierarchy. It's also possible that * the fold cannot be inserted and will be added to the list * of blocked folds. * * @param fold fold to add * @return true if the fold was successfully added to hierarchy * or false if it could not be added and became blocked. */ boolean addFold(Fold fold) { if (debug) { /*DEBUG*/System.err.println("addFold: " + fold); // NOI18N } return addFold(fold, null); } /** * Recursive method to add fold under the given parent. * * @param fold non-null fold to be inserted into hierarchy * @param parentFold parent fold under which to insert. If it's null * then attempt to use hints from lastOperationFold and lastOperationIndex. * The explicit passing of root fold can be used to force to ignore the hints. * @return true if the fold was successfully added or false if it became blocked. */ private boolean addFold(Fold fold, Fold parentFold) { int foldStartOffset = fold.getStartOffset(); int foldEndOffset = fold.getEndOffset(); int foldPriority = getOperation(fold).getPriority(); int index; boolean useLast; // use hints from lastOperationFold and lastOperationIndex if (parentFold == null) { // attempt to guess parentFold = lastOperationFold; if (parentFold == null // no valid guess || foldStartOffset < parentFold.getStartOffset() || foldEndOffset > parentFold.getEndOffset() ) { // Use root fold parentFold = execution.getRootFold(); index = FoldUtilitiesImpl.findFoldInsertIndex(parentFold, foldStartOffset); useLast = false; } else { index = lastOperationIndex; useLast = true; } } else { // already valid parentFold (do not use last* vars) index = FoldUtilitiesImpl.findFoldInsertIndex(parentFold, foldStartOffset); useLast = false; } // Check whether the index is withing bounds int foldCount = parentFold.getFoldCount(); if (useLast && index > foldCount) { index = FoldUtilitiesImpl.findFoldInsertIndex(parentFold, foldStartOffset); useLast = false; } // Fill in the prevFold variable // and verify that the guessed index is correct - startOffset // of the prev fold must be lower than foldStartOffset // and start offset of the next fold must be greater than foldStartOffset Fold prevFold; // fold that precedes fold being added if (index > 0) { prevFold = parentFold.getFold(index - 1); if (useLast && foldStartOffset < prevFold.getStartOffset()) { // bad guess index = FoldUtilitiesImpl.findFoldInsertIndex(parentFold, foldStartOffset); useLast = false; prevFold = (index > 0) ? parentFold.getFold(index - 1) : null; } } else { // index == 0 prevFold = null; } // Fold that will follow the fold being inserted // By default guess it's the fold at "index" but it may be a fold // at higher index as well. Fold nextFold; if (index < foldCount) { // next fold exists nextFold = parentFold.getFold(index); if (useLast && foldStartOffset >= nextFold.getStartOffset()) { // bad guess index = FoldUtilitiesImpl.findFoldInsertIndex(parentFold, foldStartOffset); useLast = false; prevFold = (index > 0) ? parentFold.getFold(index - 1) : null; nextFold = (index < foldCount) ? parentFold.getFold(index) : null; } } else { // index >= foldCount nextFold = null; } // Check whether the fold to be added overlaps // with previous fold (it's start offset is before end offset // of the previous fold. // Check whether end offset of the fold // does not overlap with folds that would follow it boolean blocked; // Index hints: // null - no overlapping (clear insert of start offset) // length == 0 - overlapping but no children // length > 0 - overlapping and children - see inspectOverlap() int[] prevOverlapIndexes; if (prevFold != null && foldStartOffset < prevFold.getEndOffset()) { // overlap if (foldEndOffset <= prevFold.getEndOffset()) { // fold fully nested // Nest into prevFold return addFold(fold, prevFold); } else { // fold overlaps with prevFold if (foldPriority > getOperation(prevFold).getPriority()) { // can replace if (prevFold.getFoldCount() > 0) { // must check children too prevOverlapIndexes = inspectOverlap(prevFold, foldStartOffset, foldPriority, 1); if (prevOverlapIndexes == null) { // blocked // "addFoldBlock" var was assigned by inspectOverlap() blocked = true; } else { // not blocked blocked = false; } } else { // prevFold has no children blocked = false; prevOverlapIndexes = EMPTY_INT_ARRAY; } } else { // cannot remove -> overlaps blocked = true; addFoldBlock = prevFold; prevOverlapIndexes = null; } } } else { // no overlapping with prevFold -> insert after blocked = false; prevOverlapIndexes = null; } if (!blocked) { // Which fold will be the next important for the insert (possibly overlapped) int nextIndex = index; // Non-null in case of active overlapping for foldEndOffset int[] nextOverlapIndexes = null; if (nextFold != null) { // next fold exists if (foldEndOffset > nextFold.getStartOffset()) { // End inside or after the current fold if (foldEndOffset >= nextFold.getEndOffset()) { // Fold ends after end offset of the current nextFold // Find the fold in (or after) which the inserted fold really ends. // Do binary search to have deterministic non-linear perf // Third param is false i.e. get possibly last fold // in multiple empty folds (same like in findFoldInsertIndex()) nextIndex = FoldUtilitiesImpl.findFoldStartIndex(parentFold, foldEndOffset, false); // nextIndex should not be -1 - otherwise should not reach this code nextFold = parentFold.getFold(nextIndex); } if (foldEndOffset < nextFold.getEndOffset()) { // ends inside if (foldPriority > getOperation(nextFold).getPriority()) { // remove next fold if (nextFold.getFoldCount() > 0) { // next has children nextOverlapIndexes = inspectOverlap(nextFold, foldEndOffset, foldPriority, 1); if (nextOverlapIndexes == null) { // blocked // "addFoldBlock" var was assigned by inspectOverlap() blocked = true; } // can remove nested folds } else { // nextFold has no children => can be removed nextOverlapIndexes = EMPTY_INT_ARRAY; } } else { // blocked by next fold blocked = true; addFoldBlock = nextFold; } } else { // fold ends after bounds of nextFold but prior start of next fold nextIndex++; // insert clearly after the nextFold } } // fold ends before start offset of nextFold => insert normally later } // next fold does not exist - no folds at index or after it if (!blocked) { // Here it should be possible to insert the fold // prevOverlapIndexes and nextOverlapIndexes need to be resolved first // (and the possible index shift consequences) // Finally the lastOperationFold and lastOperationIndex // should be set for future use. if (prevOverlapIndexes != null) { int replaceIndexShift; if (prevOverlapIndexes.length == 0) { // no children replaceIndexShift = 0; } else { // children replaceIndexShift = removeOverlap(prevFold, prevOverlapIndexes, fold); // Must shift nextIndex by number of replaced children nextIndex += prevFold.getFoldCount(); } removeFoldFromHierarchy(parentFold, index - 1, fold); index += replaceIndexShift - 1; // -1 for removed prevFold nextIndex--; // -1 for removed prevFold } if (nextOverlapIndexes != null) { int replaceIndexShift; if (nextOverlapIndexes.length == 0) { // no children replaceIndexShift = 0; } else { // children replaceIndexShift = removeOverlap(nextFold, nextOverlapIndexes, fold); } removeFoldFromHierarchy(parentFold, nextIndex, fold); nextIndex += replaceIndexShift; } ApiPackageAccessor.get().foldExtractToChildren(parentFold, index, nextIndex - index, fold); // Update affected offsets updateAffectedOffsets(fold); markFoldAddedToHierarchy(fold); processUnblocked(); } } if (blocked) { // Fold is blocked - "addFoldBlock" var holds the blocker execution.markBlocked(fold, addFoldBlock); addFoldBlock = null; // enable GC } // Remember hints for next call lastOperationFold = parentFold; lastOperationIndex = index + 1; return !blocked; } /** * Nested check of possibility of inserting a fold. * * @param fold that has at least one child fold. Folds with empty * children cannot be used here. * @param offset of inserting * @param priority of the fold * @param level nesting level of check - starting at 1 * @return array of ints containing deepest-level + 1 entries * where each item presents the index of the overlapped item * that needs to be removed. The first array item * is either 0 - clean insert after the index inside the deepest level * or 1 - overlapping but removable (has no children). *
* null is returned if folds overlap but priority * of present fold is higher so the attempted fold will become blocked. * checkOverlapBlock will be filled with the deep fold * that actually blocks. * *

* Example:

     *   [0] = 0   - clean insert after fold at index 5
     *   [1] = 2   - overlapping with fold at index 2 at level 1
     *   [2] = 5   - deepest level ?overlapping? => no, index 0 says clean insert
     *   
* *

* Example 2:

     *   [0] = 1   - overlap with fold at index 4 (fold will be removed)
     *   [1] = 1   - overlapping with fold at index 1 at level 1
     *   [2] = 4   - deepest level ?overlapping? => yes, index 0 says overlapping
     *   
*/ private int[] inspectOverlap(Fold fold, int offset, int priority, int level) { int index = FoldUtilitiesImpl.findFoldStartIndex(fold, offset, false); int[] result; Fold indexFold; if (index >= 0 && FoldUtilities.containsOffset( (indexFold = fold.getFold(index)), offset) ) { if (priority > getOperation(indexFold).getPriority()) { // can be replaced if (indexFold.getFoldCount() > 0) { // has non-empty children result = inspectOverlap(indexFold, offset, priority, level + 1); if (result != null) { // no blocking in children result[level] = index; } // result == null => blocking in children } else { // has no or empty children result = new int[level + 1]; result[0] = 1; // overlapping at the last level result[level] = index; // will later insert at index 0 } } else { // higher priority of existing fold -> return null addFoldBlock = indexFold; // remember the blocking fold result = null; } } else { // before first child fold or no overlapping result = new int[level + 1]; result[0] = 0; // clearly nested result[level] = index; // will later insert at index 0 } return result; } /** * Remove overlapping folds based on information from previous call * to inspectOverlap(). * * @param fold fold which blocking children will be removed. The fold itself * will remain (must be removed by caller). * @param indexes indexes array obtained by previous call to inspectOverlap(). * @param block blocking fold that will be used when marking the removed * children as blocked. * * @return fold insert index that corresponds to the originally used offset. */ private int removeOverlap(Fold fold, int[] indexes, Fold block) { int indexShift = 0; // how many new children was inserted prior to offset int indexesLengthM1 = indexes.length - 1; for (int i = 1; i < indexesLengthM1; i++) { int index = indexes[i] + indexShift; removeFoldFromHierarchy(fold, index, block); indexShift += index; } // Need to process last (most inner) fold int index = indexes[indexesLengthM1] + indexShift; if (indexes[0] == 0) { // clearly nested after the fold index++; // move after the fold } else { // indexes[0] == 1 => remove the overlap fold removeFoldFromHierarchy(fold, index, block); } return index; } /** * Physically remove the fold from the hierarchy and update the appropriate * state variables. */ private void removeFoldFromHierarchy(Fold parentFold, int index, Fold block) { Fold removedFold = ApiPackageAccessor.get().foldReplaceByChildren(parentFold, index); updateAffectedOffsets(removedFold); markFoldRemovedFromHierarchy(removedFold); unblockBlocked(removedFold); if (block != null) { execution.markBlocked(removedFold, block); } } /** * Remove the block that was removed from hierarchy * because of adding of another fold. Remember * all folds that were blocked by the remove block * because they will be attempted to be reinserted * prior committing of this transaction. */ private void unblockBlocked(Fold block) { Set blockedSet = execution.unmarkBlock(block); if (blockedSet != null) { for (Iterator it = blockedSet.iterator(); it.hasNext();) { Fold blocked = (Fold)it.next(); int priority = getOperation(blocked).getPriority(); while (unblockedFoldLists.size() <= priority) { unblockedFoldLists.add(new ArrayList(4)); } ((List)unblockedFoldLists.get(priority)).add(blocked); if (priority > unblockedFoldMaxPriority) { unblockedFoldMaxPriority = priority; } } } } /** * Attempt to reinsert the folds unblocked by particular add/remove operation. */ private void processUnblocked() { if (unblockedFoldMaxPriority >= 0) { // some folds became unblocked for (int priority = unblockedFoldMaxPriority; priority >= 0; priority--) { List foldList = (List)unblockedFoldLists.get(priority); Fold rootFold = execution.getRootFold(); for (int i = foldList.size() - 1; i >= 0; i--) { // Remove last fold from the list Fold unblocked = (Fold)foldList.remove(i); if (!execution.isAddedOrBlocked(unblocked)) { // not yet processed unblockedFoldMaxPriority = -1; // Attempt to reinsert the fold - random order - use root fold addFold(unblocked, rootFold); if (unblockedFoldMaxPriority >= priority) { throw new IllegalStateException("Folds removed with priority=" // NOI18N + unblockedFoldMaxPriority); } if (foldList.size() != i) { throw new IllegalStateException("Same priority folds removed"); // NOI18N } } } } } unblockedFoldMaxPriority = -1; } private void markFoldAddedToHierarchy(Fold fold) { // Check and remove from removedFromHierarchySet if marked removed if (removedFromHierarchySet == null || !removedFromHierarchySet.remove(fold)) { if (addedToHierarchySet == null) { addedToHierarchySet = new HashSet(); } addedToHierarchySet.add(fold); } } private void markFoldRemovedFromHierarchy(Fold fold) { // Check and remove from addedToHierarchySet if marked added if (addedToHierarchySet == null || !addedToHierarchySet.remove(fold)) { if (removedFromHierarchySet == null) { removedFromHierarchySet = new HashSet(); } removedFromHierarchySet.add(fold); } } private void updateAffectedOffsets(Fold fold) { updateAffectedStartOffset(fold.getStartOffset()); updateAffectedEndOffset(fold.getEndOffset()); } /** * Extend affectedStartOffset in downward direction. */ private void updateAffectedStartOffset(int offset) { if (offset < affectedStartOffset) { affectedStartOffset = offset; } } /** * Extend affectedEndOffset in upward direction. */ private void updateAffectedEndOffset(int offset) { if (offset > affectedEndOffset) { affectedEndOffset = offset; } } private void checkNotCommitted() { if (committed) { throw new IllegalStateException("FoldHierarchyChange already committed."); // NOI18N } } }
... 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.