Skip navigation links
org.netbeans.modules.editor.fold/1 1.57

Editor Code Folding
Official

The Code Folding was created to address requirements described in Code Folding UI Specification

See: Description

Editor Code Folding 
Package Description
org.netbeans.api.editor.fold  
org.netbeans.spi.editor.fold  

The Code Folding was created to address requirements described in Code Folding UI Specification

It is a module located under /cvs/editor/fold directory.

It consists of

Code Folding defines CodeFoldingAPI.

The Javadoc documentation can be generated by using

    cd /cvs/editor/fold
    ant javadoc

What is New (see all changes)?

Use Cases

API Use Cases

Exploring of the Folds

The code folding structure (fold hierarchy) relates to javax.swing.JTextComponent instance in one-to-one relationship.
To find the code folding hierarchy instance for the given non-null text component the following code snippet can be used:

    JTextComponent editorComponent = ...
    FoldHierarchy hierarchy = FoldHierarchy.get(editorComponent);

Explore the Folds Hierarchy

The tree-based hierarchy has one non-removable and non-collapsable root fold that covers the whole document. It can be obtained by

    FoldHierarchy foldHierarchy = ...
    Fold rootFold = hierarchy.getRootFold();

The children folds of the root fold (or children folds) can be obtained by

    // the hierarchy must be locked prior exploration or manipulation
    hierarchy.lock();
    try {
        Fold rootFold = ...
        int foldCount = rootFold.getFoldCount();
        for (int i = 0; i < foldCount; i++) {
            Fold childFold = rootFold.getFold(i);
        }
    } finally {
        hierarchy.unlock();
    }

Index of the child in its parent can be found by

    hierarchy.lock();
    try {
        Fold rootFold = ...
        int foldIndex = rootFold.getFoldIndex(childFold);
    } finally {
        hierarchy.unlock();
    }

Collapse Nearest Fold

In the given fold hierarchy find the nearest fold right at or after the given offset and collapse it.

    hierarchy.lock();
    try {
        Fold fold = FoldUtilities.findNearestFold(hierarchy, offset);
        hierarchy.collapse(fold);
    } finally {
        hierarchy.unlock();
    }

Expand All Folds

In the given fold hierarchy expand all folds that are currently collapsed.

    FoldUtilities.expand(hierarchy, null);

Collapse All Folds of Certain Type

In the given fold hierarchy collapse all e.g. javadoc folds that are currently collapsed.
The example can be generalized to any fold type.

    FoldUtilities.collapse(hierarchy, JAVADOC_FOLD_TYPE);

Start Listening on Fold Hierarchy Changes

In the given fold hierarchy start to listen on all changes done in the hierarchy.
This is actually used e.g. in the Editor's View Hierarchy that needs to refresh views based on the fold changes.

    hierarchy.addFoldHierarchyListener(new FoldHierarchyListener() {
        public void foldHierarchyChanged(FoldHierarchyEvent evt) {
            // Hierarchy does not need to be locked here
            //
            // evt.getAffectedStartOffset() and getAffectedEndOffset()
            // give text area affected by the fold changes in the event
        }
    });

Inspect Collapsed Folds in Affected Area

Listen on the hierarchy changes and refresh the views in the text area affected by the fold change.
Inspect the collapsed folds in the affected area because special views need to be created for the collapsed folds.
The actual code in the View Hierarchy is somewhat different but the one given here is more descriptive.

    hierarchy.addFoldHierarchyListener(new FoldHierarchyListener() {
        public void foldHierarchyChanged(FoldHierarchyEvent evt) {
            for (Iterator collapsedFoldIterator
                = FoldUtilities.collapsedFoldIterator(hierarchy,
                    evt.getAffectedStartOffset(),
                    evt.getAffectedEndOffset()
                );
                it.hasNext();
            ) {
                Fold collapsedFold = (Fold)it.next();
                // Create special view for the collapsedFold
            }
        }
    });

SPI Use Cases

Create a New Fold Manager

Manipulation of the folds is designed to be done by fold managers.
Those classes implement FoldManager interface in the SPI.
At initialization time they are given instance of FoldOperation through which they can create, add or remove the fold instances.

To create and use a new FoldManager instance it's necessary to

  • Define the class of the FoldManager.
        public class MyFoldManager implements FoldManager { // or extends AbstractFoldManager
    
            ...
    
        }
    
  • Create FoldManagerFactory for the FoldManager.
    
        public class MyFoldManager ...
    
            ...
    
            public static final class Factory implements FoldManagerFactory {
    
                public FoldManager createFoldManager() {
                    return new MyFoldManager();
                }
    
            }
    
        }
    
  • Register FoldManagerFactory into xml layer into the directory "Editors/<mime-type>/FoldManager/"
  • Enable Code Folding in editor's Settings initializer (please see e.g. NbJavaSettingsInitializer)
    
        public class MySettingsInitializer ...
    
            public void updateSettingsMap(Class kitClass, Map settingsMap) {
                ...
                settingsMap.put(SettingsNames.CODE_FOLDING_ENABLE, Boolean.TRUE);
            }
    
        }
    

Create a New Fold by Fold Manager

Create a new fold and add it to the hierarchy. The operation is performed by the fold manager either at initialization phase (in the initFolds() which gets called automatically by the infrastructure) or at any other time when the fold manager's operation gets invoked (usually by a listener that the fold manager attaches to be notified about changes that can cause the folds structure to be changed - e.g. a parsing listener for java folds).

Operations that manipulate the hierarchy are done in terms of a valid transaction over the fold hierarchy.
Transactions allow to fire the collected changes as a single FoldHierarchyEvent at the time when they are committed.

    // In the FoldManager's context
    FoldOperation operation = getOperation();
    FoldHierarchyTransaction transaction = operation.openTransaction();
    try {
        Fold fold = operation.createFold(...);
        operation.addFoldToHierarchy(fold, transaction);
    } finally {
        transaction.commit();
    }

Remove Fold from Hierarchy by Fold Manager

Remove the existing fold from the hierarchy

    // In the FoldManager's context
    FoldOperation operation = getOperation();
    FoldHierarchyTransaction transaction = operation.openTransaction();
    try {
        Fold fold = ...
        operation.removeFoldFromHierarchy(fold, transaction);
    } finally {
        transaction.commit();
    }

Updating Fold hierarchy

In the preceding cases, maintaining Folds was the FoldManager's responsibility. The FoldManager typically held a copy of the Folds added to the hierarchy, and during the refresh, it compared them to the new data and decided what folds to remove. For simple cases, which only create/remove folds based on text positions, part of the work can be offloaded to the FoldOperation:
    // create new fold positional information for all folds.
    Collection<FoldInfo> newInfos = ...;
    
    // create FoldInfo for each of the fold
    newInfos.add(
        FoldInfo.range(start, end, type).
            withTemplate(customTemplate).
            withDescription(veryCustomDescription).
            collapse(true)
    );
    
    // the hierarchy must be locked prior to update
    
    doc.readLock();
    hierarchy.lock();
    try {
        operation.update(newInfos, null, null);
    } finally {
    }
The update() operation performs a diff, creates new folds, discards old ones, and updates the folds, which prevailed.

Accessing folds

Instead of keeping a copy of created folds, the FoldManager may call operation.foldIterator. The iterator will enumerate all folds, including (recursively) blocked ones.

Exported Interfaces

This table lists all of the module exported APIs with defined stability classifications. It is generated based on answers to questions about the architecture of the module. Read them all...
Group of java interfaces
Interface NameIn/OutStabilitySpecified in What Document?
CodeFoldingAPIExportedOfficial

Implementation Details

Where are the sources for the module?

The sources for the module are in the Apache Git repositories or in the GitHub repositories.

What do other modules need to do to declare a dependency on this one, in addition to or instead of a plain module dependency?
Nothing.

Read more about the implementation in the answers to architecture questions.

Skip navigation links
org.netbeans.modules.editor.fold/1 1.57