See: Description
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
The Javadoc documentation can be generated by using
cd /cvs/editor/fold ant javadoc
FoldTypes
can be defined for a mime type by FoldTypeProviders
. They
can form a type hierarchy. FoldUtilities
provide methods to check fold enablement and
available FoldTypes. Working directly with Preferences is not advised.
Fold can provide offsets to start and end of its content excluding guard areas. FoldingSupport
provides factories for comment-driven FoldManager
and for fold ContentReader
capable
of reading javadoc-style comments or similar.
FoldOperation
allows to update
folds with FoldInfos
, removing, adding
or updating Folds as necessary. Existing FoldManagers can be simplified. Folds can be defined wihtout
initial state - the state will be determined form the options by the infrastructure. All folds defined
by a FoldManager can be retrieved from FoldOperation.foldIterator()
, even though they are
blocked.
FoldHierarchyMonitor
was introduced to allow hooking into UI when
a FoldHierarchy is produced for a JTextComponent. The 'active' flag is provided on
the FoldHierarchy
to determine whether the hierarchy be popuplated with folds
at all.
Using FoldingSupport
utility class, clients can create instance of
FoldManager
that creates folds based on comments, previously CustomFoldManager
in editor.lib module.
Added FoldOperation.owns(Fold) to check whether fold was produced by a particular FoldOperation.
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);
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(); }
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(); }
In the given fold hierarchy expand all folds that are currently collapsed.
FoldUtilities.expand(hierarchy, null);
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);
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 } });
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 } } });
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
public class MyFoldManager implements FoldManager { // or extends AbstractFoldManager ... }
public class MyFoldManager ... ... public static final class Factory implements FoldManagerFactory { public FoldManager createFoldManager() { return new MyFoldManager(); } } }
NbJavaSettingsInitializer
)
public class MySettingsInitializer ... public void updateSettingsMap(Class kitClass, Map settingsMap) { ... settingsMap.put(SettingsNames.CODE_FOLDING_ENABLE, Boolean.TRUE); } }
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 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(); }
// 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.
operation.foldIterator
. The iterator
will enumerate all folds, including (recursively) blocked ones.
|
The sources for the module are in the Apache Git repositories or in the GitHub repositories.
Read more about the implementation in the answers to architecture questions.