How to use certain NetBeans APIs

This page contains extracted usecases for some of the NetBeans modules that offer an API.

How to use Debugger Core API?

The debuggercore/api module (Debugger Core API) allows to install different debugger implementation to one IDE. It allows to share some common UI components.

UseCase I. - Install and use CPP debugger plug-in to NetBeans + Java Debugger.

CPP debugger plug-in installs support for debugging of some new language to the NetBeans IDE, and some new debugging engine. This implementation of debugger should share UI components (actions, Debugger Views, ...) with default NB Java Debugger. It should share basic debugger model too - notion of current context, current session, thread, call stack line, ...

CPP debugger plug-in installs:

UseCase II. - Install and use JSP debugger plug-in to NetBeans + Java Debugger.

JSP debugger plug-in installs support for debugging of some new language to the NetBeans Java Debugger. It does not contain a new debugger engine, but it delegates to standard NB Java debugger. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

JSP debugger plug-in installs:

UseCase III. - Install and use J2EE debugger plug-in to NetBeans + Java Debugger.

J2EE debugger plug-in installs some enhancements to the standard Java Debugger. It does not contain a new debugger engine or language support. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

J2EE debugger plug-in installs:

UseCase IV. - Install and use DBX debugger plug-in to NetBeans.

DBX debugger plug-in installs support for debugging of some new language (CPP) to the NetBeans IDE, and some new debugging engine. But it contains debugger engine for Java debugging too. DBX debugger engine has its own session management (or will have in the next versions). One debugger engine can manage more than one sessions. One engine supports debugging in more than one language.

UseCase V. - Implement Debugger Core UI module on top of Debugger Core API / SPI.

Debugger Core UI needs:


How to use Debugger JPDA API?

The debuggerjpda/api (Debugger JPDA API) defines API for NetBeans Java Debugger.

UseCase I. - Install and use CPP debugger plug-in to NetBeans + Java Debugger.

CPP debugger plug-in installs support for debugging of some new language to the NetBeans IDE, and some new debugging engine. This implementation of debugger should share UI components (actions, Debugger Views, ...) with default NB Java Debugger. It should share basic debugger model too - notion of current context, current session, thread, call stack line, ...

CPP debugger plug-in installs:

UseCase II. - Install and use JSP debugger plug-in to NetBeans + Java Debugger.

JSP debugger plug-in installs support for debugging of some new language to the NetBeans Java Debugger. It does not contain a new debugger engine, but it delegates to standard NB Java debugger. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

JSP debugger plug-in installs:

UseCase III. - Install and use J2EE debugger plug-in to NetBeans + Java Debugger.

J2EE debugger plug-in installs some enhancements to the standard Java Debugger. It does not contain a new debugger engine or language support. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

J2EE debugger plug-in installs:

UseCase IV. - Install and use DBX debugger plug-in to NetBeans.

DBX debugger plug-in installs support for debugging of some new language (CPP) to the NetBeans IDE, and some new debugging engine. But it contains debugger engine for Java debugging too. DBX debugger engine has its own session management (or will have in the next versions). One debugger engine can manage more than one sessions. One engine supports debugging in more than one language.


How to use java/api?

Models basic aspects of the metadata surrounding Java source files, such as the classpath. More information in the Javadoc.

The API is widely used by all sorts of IDE modules which need to work with Java sources. They can obtain the classpath or boot classpath for a file (if there is one), find out where its source root is, find sources corresponding to bytecode class files, find all sources or classpaths corresponding to open projects, find Javadoc, etc. The SPI is intended mainly for Java platform and library providers, and project type providers, to declare all of this information.


How to use NetBeans Metadata Repository?

See answer to the use-cases question.

The MDR should be used for data-integration accross different modules in the IDE. An example usecase can be found at http://mdr.netbeans.org/example.html. Basic usecases can also be found in the overview of individual API packages in javadoc.

How to use Progress API?

The progress API is good for tracking progress of long lasting tasks in the IDE.

Basic usage

There are 3 types of progress indication:

The default location of the progress indication is the status bar which aggregates all tasks running in the IDE that show progress. However it's possible to exclude the task from the default location and show the progress in one's custom dialog component. In such a case the same task should not appear in the status line component as well.

It's possible to request cancelling the task from status line progress aggregator if the task allows cancelling.

Progress tasks that get started as a result of explicit user action takes precedence in the status line docked component over tasks that are triggered by the system. (say filesystem refresh for example)

The most common usecase of the API looks like this:

ProgressHandle handle = ProgressHandleFactory.creatHandle("My custom task");
...
// we have 100 workunits
// at this point the task appears in status bar.
handle.start(100);
...
handle.progress(10);
...
handle.progress("half way through", 50);
...
handle.progress(99);
// at this point the task is finished and removed from status bar
// it's not realy necessary to count all the way to the limit, finish can be called earlier.
// however it has to be called at the end of the processing.
handle.finish();

Advanced Usage

In case your usage of the API

then you should consider using the aggregating version of APIs which is similar to the simple APIs but has distinctive differences and additions that allow for more complex scenarios.

It allows to compose the progress bar from 1+ independent sources, all sharing proportional piece of the progress bar. Additionally you can monitor the task's overall progress from one central place and possibly add more contributing sources of the progress during processing.

        // let's have a factory for client code that performs some part of the job to be done..
        Lookup.Result res = Lookup.getDefault().lookup(new LookupTemplate(MyWorkerFactory.class));
        Iterator it = res.allInstances().iterator();
        ProgressContributor[] contribs = new ProgressContributor[res.allInstances().size()];
        int i = 0;
        while (it.hasNext()) {
            MyWorkerFactory prov = (MyWorkerFactory)it.next();
            contribs[i] = AggregateProgressFactory.createProgressContributor("Module X contribution");
            MyWorker worker = prov.createWorker(contribs[i]);
            //... snip ... do something with the worker..
            i = i + 1;
        }
        AggregateProgressHandle handle = AggregateProgressFactory.createHandle("My Task", contribs, null, null);
        // non-cancellable and with out output link.
        
        // calling start() at the time when the actual long running task starts processing
        handle.start("here we go");
        // ...snip...
        // now the individual MyWorker instances log their progress.
        // possibly in other threads too..
        // ... snip...
        // 
        if (myConditionThatSpawnsAnotherContributor()) {
            ProgressContributor cont = AggregateProgressFactory.createProgressContributor("Additional exceptional contribution");
            handle.addContributor(cont);
            // ... snip ...
        }
        
        // the task is finished when all the ProgressContributors finish..

How to use editor/codetemplates?

Code Templates allow to paste various code snippets by using parametrized text. The parameters of the same name will share the same default value and if that value gets changed by user's typing the new value gets replicated into all the parameter's occurrences. Code Templates replace the original abbreviations functionality. Code template's example for (Iterator ${iterator} = ${collection instanceof="java.util.Collection"}.iterator(); ${iterator}.hasNext();) { ${cursor}${iterator}.next();" } Each parameter can have additional hints of what values can be assigned to it. The hint has a form ${param hint=value} or just ${param hint} which translates to ${param hint="true"} If necessary the value of the hint can be enclosed in quotes to allow to write whitespace or { or } into the value. The quote can be written by using \". Reserved parameter names ${cursor} defines position where the caret will be located after the editing of the code template default values will finish. Reserved hint names ${param editable=false} can be used to make the parameter to be skipped from user's editing. This may be useful e.g. with using java-specific type hint (described below). Java: ${ind index} defines that the default value of the parameter should be an unused variable in the given context named i. If i is already used then j is attempted or then k etc. until z. Then i0, i1 etc. are attempted. ${param type="java.util.Collection"} defines java type that the parameter must be instance of. Besides class names there can be array e.g. String[] or generics java.util.List<String> ${param array} defines parameter of array type (including arrays of primitive data types). ${param type="java.util.Iterator"} defines that the parameter has the given java type. The template processing infrastructure will use short name Iterator and import java.util.Iterator.

Code Template Parameters

One of the main benefits of the code templates is their parametrization which allows to substitute the default values for the parameters before the final insertion and it also allows the user to modify these default values explicitly after the code template gets inserted into the document.
The parameters are marked in the code template's text by ${...}.
Parameters of the same name benefit from automatic replication. Once the template gets pasted into the document all the parameter's occurrences get replaced by parameter's default value.
The first parameter's occurrence gets selected.
The user can now replace the default value. If the user does so the new value gets replicated to all the other occurrences of this parameter automatically.

Mime-type specific operation

Each code template needs to find the default values for its parameters before it gets inserted into the text.
Sometimes it's enough to just specify the default value in the template's text but usually the default value gets determined from the context of insertion.
There is an intent to create a mime-type specific code template processor that would be registered per mime-type. There could be even more than one such processors processing the template in a specific order.

Parameter hints

Besides parameter's name the template processors may need additional hints of how to find a default value for the parameter.
For example java code template's parameter may be an index parameter which means that the infrastructure should fill in a fresh index variable e.g. i.
Or the parameter can only be of a certain java type such as in the case of iterating through a collection the type must be subtype of java.util.Collection.
These requirements could be specified as additional hints to the parameters e.g. ${i index} or ${c instanceof=java.util.Collection}.
The hints allow string literals to support arbitrary explicit default values specifications e.g. ${x default="Hello world"}.
The '{' and '}' have no special meaning inside the string literal.
The '"' char is allowed to be used by escaping ${x default="\"quoted string\""}.

Temporary Code Templates

The Code Completion functionality allows to build temporary Code Templates functionality if it could build a temporary template for completing of the method parameters. The parameters could be completed one by one by tabbing and the Code Templates framework would fill in proper default values just like it does for regular templates.

Insert Text Building and Updating

The parametrized text of the code template first gets parsed and the parameters get their default values which by default are the names of the parameters. The code template processor are then called to update this default value.
The new java infrastructure being developed would benefit from the possibility to obtain the full string containing the skeleton of the code template (without parameters) with the present default values. It can take that string and locally parse it to find out types of local variables used in the particular template and fill in dependent variable types.

Parameter Editability

Certain part of the code template may change text but it should not be edited by the user. For example when iterating over collection given as a parameter the collection may be generics-ed by additional type. The iterator's variable type then also needs to generics-ed with the same type.
The iterator's type parameter should not be editable because this operation may be done automatically by the java code template processor.
There should be a hint editable having true/false.

How to use Editor Code Completion?

Code Completion provides users with a list of suggested completions for partially typed texts in the editor and various dialog input fields. The Code Completion module was created to replace the original legacy editor code completion which lacked several key requirements: Support for multiple independent code completion content providers. Implied requirement for ordering and prioritization of the completion items. Direct support for asynchronous completion result computation. Missing separation to the API and SPI and implementation parts.

API

Show or hide completion window

The API is small and it only allows to explicitly show or hide the completion window.
It's being used by code templates that need to explicitly show the code completion window when tabbing to a particular parameter.
There may be certain actions that want to ensure that the code completion is hidden at the time when they are invoked. For example the actions pasting the content of the completion item into the document.

SPI

Provide completion content by independent providers

Completion infrastructure needs to obtain the results that are then displayed in the completion window.
There are three types of displayed results related to the current caret offset:

For the purpose of obtaining these completion results CompletionProvider exists.
There may be an arbitrary number of independent completion providers for a single completion popup window.
The completion providers are registered through the xml layer into Editors/<mime-type>/CompletionProviders. Once the document with the particular mime-type gets loaded the corresponding completion providers will get instantiated and used.

Threading:
The code completion's infrastructure invokes the requests for the completion results in the AWT thread.
Therefore all the methods of the completion providers are invoked in AWT thread but they may reschedule their processing into other threads.

Provide completion results computed asynchronously

The completion provider creates a task that computes the resulting data that will then be displayed by the code completion infrastructure.
The task creation and computation are called synchronously from the AWT event dispatch thread.
However there can be potentially long-running tasks (e.g. working with MDR) that are not desirable to be run in AWT thread.
Therefore the completion infrastructure provides a listener to which the completion task notifies the results.
The support class AsyncCompletionTask allows to post the task computation into RequestProcessor.

Provide list of completion items fulfilling various requirements

The completion task computes a collection of completion items which are then collected by the completion infrastructure and displayed.
Displaying. Each completion item must be able to display itself in a JList.
Sorting. The completion items may come from different completion providers and they must be sorted before displaying. The sort order should not only be alphabetical but it should also allow a prioritization of the items according to their importance in the given context.
Actions. The interaction of the user with the completion item is done by interacting with item's input map and action map.
Documentation. The item may want to display additional detailed information in a documentation popup window.


How to use Error Stripe?

The Error Stripe shows an overview of important information of an edited source code. It shows this information for the whole source code (regardless of its size).

Augment Annotations to be shown in the Error Stripe

Use the OpenIDE Text API.

Provide Up-to-date Status for the Error Stripe

A module in the IDE has information whether data shown in the Error Stripe is up-to-date or not. The Error Stripe may change the appearance according to this knowledge.

Implement the UpToDateStatusProvider that provides up-to-date status. Be sure that it fires PropertyChangeEvent when this status is changed.

Implement the UpToDateStatusProviderFactory that creates an instance of your UpToDateStatusProvider for a given JTextComponent and install it as described here.


How to use editor/fold?

The Code Folding is part of the editor module functionality and it's responsible for hiding of the portions of the code that are less important for the user at the given time.

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);

Force Fold Expansion for Caret Moving Into Collapsed Fold

In the given fold hierarchy expand the fold into which the caret is going to be moved by Caret.setDot(offset).
The hierarchy must be locked and this example assumes that the underlying document is already read-locked e.g. by Document.render().

    FoldHierarchy hierarchy = FoldHierarchy.get(caretComponent);
    hierarchy.lock();
    try {
        Fold collapsed = FoldUtilities.findCollapsedFold(hierarchy, offset, offset);
        if (collapsed != null && collapsed.getStartOffset() < offset &&
            collapsed.getEndOffset() > offset) {
            hierarchy.expand(collapsed);
        }
    } finally {
        hierarchy.unlock();
    }

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

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();
    }

How to use editor/mimelookup?

Each editor provides an EditorKit which controls the policy of specific MIME content type. The policy of content type should be easily registered and found via some lookup mechanism, that will provide convenient way of using it either for kit provider or base editor infrastructure. In addition to this, the policy can be inherited, (i.e. in case of embeded kits like JSP) and the content types need to be merged in this case. MIME Lookup API should provide all mentioned requierements via easy lookup query, so content type policy user need not to solve this searching and merging on its own side.

Per mime-type operation

Operation of the editor module must be parametrized by the type of the file being edited. In the past the operation was parametrized by the class of the editor kit but that did not show up as being useful enough.
It is more practical to use a string-based parametrization concretely the mime-type. Anyone can then easily register an additional functionality for the editor because it's just enough to know the right mime-type and the type of the functionality class to be implemented and the xml layer folder where the class should be registered.
For example the editor/fold module expects to find the registered fold manager factories (org.netbeans.spi.editor.fold.FoldManagerFactory classes) in the Editors/<mime-type>/FoldManager layer folder.
The editor/completion module expects to find the registered completion providers (org.netbeans.spi.editor.completion.CompletionProvider classes) in the Editors/<mime-type>/CompletionProviders layer folder.

Provide list of instances as lookup result

On the modules' implementation side the registered functionality must be retrieved somehow. It's necessary to instantiate the registered objects and react to module enablding/disabling which can affect validity of the registered objects.
As the most convenient solution appears to use org.openide.util.Lookup allowing to provide the registered instances as a Lookup.Result allowing to listen for changes (e.g. caused by the module enabling/disabling).
This resulted into creation of class MimeLookup extends Lookup containing static MimeLookup getMimeLookup(String mimeType).

Nested mime-types

On the lexical level the document can contain nested languages.
For example JSP document can contain pieces of java code which can further contain javadoc comment tokens with nested javadoc language.
The nested languages should allow for special settings such as fonts and colors of nested syntax coloring but even things like actions that would be active in the nested document section.
This resulted into creation of MimeLookup childLookup(String mimeType) method in MimeLookup.

API Use Cases

Find class instances for the given mime-type

An API method

MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java");

can be used for getting the mime specific lookup. Having this we can lookup class or template:

Object obj = lookup.lookup(LookedUpClass.class);

or

Lookup.Result result = lookup.lookup(new Lookup.Template(LookedUpClass.class));

Getting mime-type specific child (embeded) MimeLookup

Child mime content can be embeded into parent mime content in various embeded languages. In this case mime lookup child is specified as subelement of parent lookup i.e.: MimeLookup("text/x-jsp") can have a child MimeLookup("text/x-java") in a case of a jsp scriplet.

MimeLookup lookup = MimeLookup.getMimeLookup("text/x-jsp").childLookup("text/x-java");

SPI Use Cases

Declare the mime specific object via xml layer

This is the simpliest way of declaring, it is suitable for objects stored directly in mime specific folders:
<filesystem>
    <folder name="Editors">
        <folder name="text">
            <folder name="x-java">
                <file name="org-netbeans-modules-editor-mimelookuptest-MimeSpecificObject.instance"/>
            </folder>
        </folder>
    </folder>
</filesystem>
Lookup of this object will look like:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java");
MimeSpecificObject mso = (MimeSpecificObject) lookup.lookup(MimeSpecificObject.class);

Declare the object via xml layer in some specific folder using Class2LayerFolder.

Some objects are connected to some specific folder in mime specific layer folders, i.e. FoldManagerFactory.class is placed in FoldManager subfolder in the Editors/<mime-type>/. Such objects can be registered to the specific folder using interface Class2LayerFolder. Let's register FoldManagerFactory.class to FoldManager folder. First we need to implement the interface:
public class FoldManagerClass2LayerFolder implements Class2LayerFolder{
    
    public FoldManagerClass2LayerFolder {
    }
    
    /* declaring the class */
    public Class getClazz(){
        return FoldManagerFactory.class;
    }
    
    /* assigning the declared class to folder */
    public String getLayerFolderName(){
        return "FoldManager";
    }

    /* we will not support InstanceProvider */
    public org.netbeans.spi.editor.mimelookup.InstanceProvider getInstanceProvider() {
        return null;
    }
    
}

Then we need to register it to default lookup via META-INF/services registration. We need to create a folder structure META-INF/services and place there a file org.netbeans.spi.editor.mimelookup.Class2LayerFolder with the content FoldManagerClass2LayerFolder

having this we can register appropriate object to specific folder:
<filesystem>
    <folder name="Editors">
        <folder name="text">
            <folder name="x-java">
                <folder name="FoldManager">
                    <file name="org-netbeans-modules-editor-MyFoldManagerFactory.instance"/>
                </folder>
            </folder>
        </folder>
    </folder>
</filesystem>
Lookup of this object will look like:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java");
FoldManagerFactory foldManagerFactory =  (FoldManagerFactory) lookup.lookup(FoldManagerFactory.class);
or, if there should be more instances of the FoldManagerFactory:
MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java");
Collection foldManagerFactories = lookup.lookup(new Lookup.Template(FoldManagerFactory.class)).allInstances();
Notice, that the FoldManagerFactory object is found in "FoldManager" folder. It is not necessary for client of the API to know about some folder structure.

Providing implemented MimeLookupInitializer

It is the general way of adding mime specific object into the MimeLookup. Implementation of MimeLookupInitializer should be created and registered to default lookup via META-INF/services registration. For details, please look at the simplified TestMimeLookupInitializer in mimelookup/test/unit or LayerMimeLookupInitializer.

Using InstanceProvider for declaration of compound folder objects and inheritance

Demonstration of InstanceProvider and inheritance will be used together in one use case. Example of editor context menu construction will be used. Each module can register its actions to editor context menu via xml layer. As context menu is mime type sensitive (java editor has different menu items than plain editor) the actions are registered into mime specific layer folders to subfolder "Popup". When the context menu is constructing, the xml layer is scanned for the action items located in the "Popup" subfolder of specific mime folder. In addition to this there is inheritance mechanism used to share global actions (like Cut, Copy, Paste) over all mime types context menus, thus not only the action items from actual mime type are considered. All underlaying mime types are scanned also and the result is context menu with merged action items.

For example JSP scriplet context menu should be merged from action items gathered over:
  1. Editors/Popup - this is base level for global actions like Cut, Copy, Paste
  2. Editors/text/x-jsp/Popup - items from jsp mime type
  3. Editors/text/x-jsp/text/x-java/Popup - items specific to java scriplet in JSP document

For now, this construction mechanism is implemented in editor module in NbEditorKit class. The code responsible for construction is quite large, and it is not very generic, now it supports only base level + mime specific level merging. Embeded languages like example in JSP scriplet are not supported. MimeLookup will solve also this embeding and the gathering of the context menu items will looks such simply as:

MimeLookup lookup = MimeLookup.getMimeLookup("text/x-jsp").childLookup("text/x-java");
PopupActions actions = (PopupActions) lookup.lookup(PopupActions.class);
List popupActions = actions.getPopupActions();
where PopupActions is implementation of InstanceProvider and PopupActions.class needs to be registered to "Popup" subfolder using Class2LayerFolder implementation. Let's register this step by step.

Because action items are instances of various objects like:
  1. javax.swing.Action
  2. javax.swing.JSeparator
  3. org.openide.util.actions.SystemAction
  4. java.lang.String
the InstanceProvider needs to be created for this:
public class PopupActions implements InstanceProvider{
    
    List ordered;

    public PopupActions(){
    }
    
    public PopupActions(List ordered){
        this.ordered = ordered;
    }

    public List getPopupActions(){
        List retList = new ArrayList();
        for (int i = 0; i<ordered.size(); i++){
            DataObject dob = (DataObject) ordered.get(i);
            InstanceCookie ic = (InstanceCookie)dob.getCookie(InstanceCookie.class);
            if (ic!=null){
                try{
                    if (String.class.isAssignableFrom(ic.instanceClass()) ||
                        Action.class.isAssignableFrom(ic.instanceClass()) ||
                        SystemAction.class.isAssignableFrom(ic.instanceClass()) ||
                        JSeparator.class.isAssignableFrom(ic.instanceClass())){
                        Object instance = ic.instanceCreate();
                        retList.add(instance);
                    }
                }catch(IOException ioe){
                    ioe.printStackTrace();
                }catch(ClassNotFoundException cnfe){
                    cnfe.printStackTrace();
                }
            } else{
                retList.add(dob.getName());
            }
        }
        return retList;
    }

    public Object createInstance(List ordered) {
        return new PopupActions(ordered);
    }
}

This InstanceProvider needs to be declared in Class2LayerFolder implementation:
public class PopupInitializer implements Class2LayerFolder{
    
    public PopupInitializer() {
    }
    
    public Class getClazz(){
        return PopupActions.class;
    }
    
    public String getLayerFolderName(){
        return "Popup"; //NOI18N
    }

    public InstanceProvider getInstanceProvider() {
        return new PopupActions();
    }

}

Now, we just need to register PopupInitializer into default lookup via META-INF/services registration and the initialization is done.

How to use editor/settings?

Now editor settings in editor module are maintained by complicated structures and their initialization processes. It is because of historical reasons and the presence of standalone editor, where standalone settings layer is supported via openide dependent editor module layer. Each editor that provides its own settings needs to depend on the whole editor module. The main purpose of this project is to create editor/settings API, that will contain settings classes, which will be lookup-able via mimelookup. The aim is NOT to provide physical implementation of editor settings storage. The module will be just interface between the settings storage and the settings clients like <mime-type> editors, externaleditor, etc.

Per mime-type operation

The particular mime-type settings can be found for example using the following mimelookup search:
FontColorSettings fcs  = (FontColorSettings) MimeLookup.getMimeLookup("text/x-java").lookup(FontColorSettings.class);
AttributeSet fontColors = fcs.getFontColors(FontColorNames.SELECTION_COLORING);
This will resolve Fonts ant Colors settings of the coloring used for selection for the mime-type "text/x-java" in AttributeSet representation.

Listening on settings change

Settings clients often need to be able to listen on the settings change and handle this event. This can be done using mimelookup via Lookup.Template by registering LookupListener on the returned Lookup.Result.
LookupResult fontsColors  = MimeLookup.getMimeLookup("text/x-java").lookup(
    new Lookup.Template(FontColorSettings.class));
if (fontsColors !=null) {
    fontsColors.addLookupListener(new LookupListener(){
        public void resultChanged(LookupEvent ev) {
            Lookup.Result result = ((Lookup.Result)ev.getSource());
            //... settings client response on settings change
        }
    });
}

FontColorSettings implementor is responsible of creation of new instance of FontColorSettings if some setting will change in the lookup, it provides.

How to use java/platform?

Many Java-based project types need to be able to configure the version and location of Java to be used when building and running the project. This API/SPI permits these platforms to be registered and queried, and any customizations made in an appropriate GUI and persisted to disk.

The API can be used by any code wishing to know the list of installed platforms and information about each one; typically this would be used by project type providers to implement a customizer dialog. The SPI is intended to be implemented by a few modules supply support for locating and introspecting installed platforms, for example a JDK setup wizard.


How to use java/project?

Provides support infrastructure for projects working with the Java language.

Project type providers wishing to show Java packages in their logical views can use this SPI. Templates which are Java-centric can use it. Projects which wish to implement queries from the Java Support APIs can place implementations in their lookup and these will be delegated to automatically.


How to use ant/project?

Provides the basic infrastructure by which Ant-based projects can be created, read and write configuration parameters and properties from/to disk, satisfy common queries and interfaces, etc. See Javadoc and build system design document.

Mostly an SPI for use by project type providers to create the project type. Also includes a small API/SPI for other projects to find what Ant build steps are necessary to create a certain build product, for use in inter-project dependencies.

Ant project support faq:

How to use support for storing project properties?

Q: I'm creating a customizer (properties dialog) for my project type. I wan't to use the support for simple data types. What do I need to do?

You basicaly need to do two things. First create the representation of the project properties which can be used in the GUI. Second at some time convert the objects back to the ANT properties form and store them into the project.


How to use projects/libraries?

Permits libraries to be defined, customized, and stored by the user for reuse in multiple projects. For example, a Java JAR library has a classpath (usually one JAR), and an optional source path and Javadoc path that may be used for development-time features.

Different technology support modules will supply definitions of different kinds of libraries, e.g. Java JARs, that may be reused in user projects. Modules may register library predefinitions to wrap libraries they bundle. Project type providers can refer to available libraries in customizer dialogs.


How to use projects/projectapi?

Provides a generic infrastructure for modelling projects. Documentation available in the Javadoc. The build system design overview describes the basic purpose of modelling projects.

The SPI should be used by modules defining particular project types, e.g. the J2SE project type. The API is to be used primarily by GUI infrastructure and some queries, though other module code may on occasion need to refer to the API.


How to use projects/projectuiapi?

The module supplies the APIs for the basic, generic UI infrastructure for projects: list of opened projects, main project, basic project-sensitive actions, template wizards, etc.

The main use case is for project type providers to supply logical views and customizers for the project. Also for template providers to create project-aware file templates. Can also get a list of open projects, create different kinds of project-related actions, and select projects on disk.


How to use projects/queries?

General kinds of queries between modules. Queries are one way of solving the intermodule communication problem when it is necessary for some modules to obtain basic information about the system (e.g. whether a particular file is intended for version control) without needing direct dependencies on the module providing the answer (e.g. the project type which controls the file). Details are covered in the Javadoc.

Particular use cases are enumerated in the Javadoc for each query API. Usage consists of simple static method calls. Potentially a wide variety of modules could use these queries; implementations are typically registered by project type providers, though also by Java library and platform implementations.


How to use Debugger Core UI API?

The debuggercore module (Debugger Core UI) contains shared UI components for all debugger implementations, and defines some SPI for sharing of them.

UseCase I. - Install and use CPP debugger plug-in to NetBeans + Java Debugger.

CPP debugger plug-in installs support for debugging of some new language to the NetBeans IDE, and some new debugging engine. This implementation of debugger should share UI components (actions, Debugger Views, ...) with default NB Java Debugger. It should share basic debugger model too - notion of current context, current session, thread, call stack line, ...

CPP debugger plug-in installs:

UseCase II. - Install and use JSP debugger plug-in to NetBeans + Java Debugger.

JSP debugger plug-in installs support for debugging of some new language to the NetBeans Java Debugger. It does not contain a new debugger engine, but it delegates to standard NB Java debugger. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

JSP debugger plug-in installs:

UseCase III. - Install and use J2EE debugger plug-in to NetBeans + Java Debugger.

J2EE debugger plug-in installs some enhancements to the standard Java Debugger. It does not contain a new debugger engine or language support. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

J2EE debugger plug-in installs:

UseCase IV. - Install and use DBX debugger plug-in to NetBeans.

DBX debugger plug-in installs support for debugging of some new language (CPP) to the NetBeans IDE, and some new debugging engine. But it contains debugger engine for Java debugging too. DBX debugger engine has its own session management (or will have in the next versions). One debugger engine can manage more than one sessions. One engine supports debugging in more than one language.

UseCase V. - Implement Debugger Core UI module on top of Debugger Core API / SPI.

Debugger Core UI needs:


How to use Navigator API?

Navigator module is a base API module which provides: A place for modules to show structure/outline of their documents Ability for modules to show their view only when special document(node) is active in the system UI for switching between multiple views available for currently active document(node) Coalescing of fast coming selected node changes to show content for

Basic Usage Steps

In order to plug in a view into Navigator UI for certain document (data) type, module writers need to complete following steps:

Writing NavigatorPanel implementation

Implementing NavigatorPanel interface is easy, you can copy from template basic implementation BasicNavPanelImpl.java.

Advices on important part of panel implementation:

Registering NavigatorPanel impl in a layer

Declarative registration of your NavigatorPanel impl connects this implementation with specific content type, which is type of the document, expressed in mime-type syntax, for example 'text/x-java' for java sources. Infrastructure will automatically load and show your NavigatorPanel impl in UI, when currently activated Node is backed by primary FileObject whose FileObject.getMimeType() equals to content type specified in your layer.

Writing layer registration itself is easy, you can again copy from template layer Basic Navigator Registration Layer.

Additional important info:

Advanced Content Registration - Linking to Node's Lookup

There may be situations where linking between your Navigator view and activated Node's primary FileObject is not enough or not possible at all. This simply happens when the data you want to represent in Navigator are not accessible through primary FileObject or DataObject. Usual example is Multiview environment, where more views of one document exists.

The solution is to bind content of your Navigator view directly to your TopComponent. Then, whenever your TopComponent gets activated in the system, Navigator UI will show th content you connected to it.

Steps to do:

How to use View Model?

The debuggercore/ViewModel module (View Model) allows to share one TreeTableView among different modules.

Used by debugger to display various information - threads, call stack, variables, etc.

How to use Actions?

Actions provides system of support and utility classes for 'actions' usage in NetBeans.

First see the API description. Here is just a list of frequently asked or interesting questions slowly expanding as people ask them:

Actions faq:

How to define configurable Shortcut for Component based shortcut?

Q: The usual Swing way of defining Actions for your component is to create an Action instance and put it into the Input and Action maps of your component. However how to make this Action's shortcut configurable from the Tools/Keyboard Shortcuts dialog?

In order for the action to show up in Keyboards Shortcut dialog you need the action defined in the layer file under "Actions" folder and have the shortcut defined there under "Keymaps/<Profile Name>" linking to your action.

    <folder name="Actions" >
        <folder name="Window">
            <file name="org-netbeans-core-actions-PreviousViewCallbackAction.instance"/>
        </folder>
    </folder>

    <folder name="Keymaps">
        <folder name="NetBeans">
            <file name="S-A-Left.shadow">
                <attr name="originalFile" stringvalue="Actions/Window/org-netbeans-core-actions-PreviousViewCallbackAction.instance"/>
            </file>
        </folder>
    </folder>

The mentioned Action has to be a subclass of org.openide.util.actions.CallbackSystemAction. It does not necessarily has to perform the action, it's just a placeholder for linking the shortcut. You might want to override it's getActionMapKey() and give it a reasonable key.

The actual action that does the work in your component (preferably a simple Swing javax.swing.Action) is to be put into your TopComponent's ActionMap. The key for the ActionMap has to match the key defined in the global action's getActionMapKey() method.

        getActionMap().put("PreviousViewAction", new MyPreviousTabAction());

This way even actions from multiple TopComponents with the same gesture (eg. "switch to next tab") can share the same configurable shortcut.

Note: Don't define your action's shortcut and don't put it into any of the TopComponent's javax.swing.InputMap. Otherwise the component would not pick up the changed shortcut from the global context.


How to use UI Utilities API?

The org.openide.awt provides API/SPI for UI related aspects of application.

XXX no answer for arch-usecases


How to use Dialogs API?

The DialogsAPI allows creating a user notification, a dialog's description and also permits it to be displayed. The wizard framework allows create a sequence of panels which leads a user through the steps to complete any task. This API is part of package org.openide.

There is a Wizard Guide Book providing the introductionary information, moreover here is a list of frequently asked questions and their answers:

How to change the title of a wizard?

Q: Although none of my panels have names set (using setName() method) and the method name() in the WizardDescriptor.Iterator returns an empty string, I'm getting "wizard ( )" as the title of each panel in my wizard. When I set the name of the panel and return a string from the method name() I get: "panelName wizard (myName)". The wizard steps are labeled correctly, it just the panel title/name that looks like it adds "wizard ()" to any of my panels. I don't mind the "( )", but I would like to rid of the word "wizard".

A: You can change the format of your wizard's title by WizardDescriptor.setTitleFormat(MessageFormat format) and rid of 'wizard' word in the default wizard's title.


How to use Input/Output System?

The Input/Output API is a small API module which contains InputOutput and related interfaces used in driving the Output Window. The normal implementation is org.netbeans.core.output2.

There is an SPI but additional implementations are not expected. The API is most important.

Simple usage example:


InputOutput io = IOProvider.getDefault().getIO("My Window", true);
io.select();
OutputWriter w = io.getOut();
w.println("Line of plain text.");
OutputListener listener = new OutputListener() {
    public void outputLineAction(OutputEvent ev) {
        StatusDisplayer.getDefault().setStatusText("Hyperlink clicked!");
    }
    public void outputLineSelected(OutputEvent ev) {
        // Let's not do anything special.
    }
    public void outputLineCleared(OutputEvent ev) {
        // Leave it blank, no state to remove.
    }
};
w.println("Line of hyperlinked text.", listener, true);

How to use Loaders?

In summary, the LoadersAPI is responsible for scanning files in a directory on disk, weeding out irrelevant files of no interest to the IDE, and grouping the rest into logical chunks, or just determining what type of data each represents. It does this scanning by asking each registered data loader whether or not the given file(s) should be handled. The first loader to recognize a file takes ownership of it, and creates a matching data object to represent it to the rest of the IDE.

A lot of usecases is described in the javadoc. Here is the list of some faqs:

How to add action to folder's popup menu?

The actions that the default folder loader shows in its popup menu are read from a layer folder Loaders/folder/any/Actions so if any module wishes to extend, hide or reorder some of them it can just register its actions there. As code like this does:
    <folder name="Loaders" >
        <folder name="folder" >
            <folder name="any" >
                <folder name="Actions" >
                    <file name="org-mymodule-MyAction.instance" >
                        <attr name="instanceCreate" stringvalue="org.mymodule.MyAction" />
                    </file>
                </folder>
            </folder>
        </folder>
    </folder>
    
As described in general actions registration tutorial.

This functionality is available since version 5.0 of the loaders module. Please use OpenIDE-Module-Module-Dependencies: org.openide.loaders > 5.0 in your module dependencies.

In version 5.8 all the standard loaders were changed to read actions from layer:

How to allow others to enhance actions of your loader?

If you want other modules to enhance or modify actions that are visible on DataObjects produced by your DataLoader and you are either using DataNode or its subclass, you can just override protected String actionsContext() method to return non-null location of context in layers from where to read the actions.

The usual value should match Loaders/mime/type/Actions scheme, for example java is using Loaders/text/x-java/Actions, but the name can be arbitrary.

This functionality is available since version 5.0 of the loaders module. Please use OpenIDE-Module-Module-Dependencies: org.openide.loaders > 5.0 in your module dependencies.

How to use Utilities?

Described in the overall answer.

There is a great introduction to Lookup and its usage in its javadoc. Here is just a list of frequently asked or interesting questions slowly expanding as people ask them:

Lookup faq:

How to specify that a service in Lookup should be available only on Windows?

Q: Most of the time I specify interfaces that I want to add to the Lookup class in the layer.xml file. But, let's say I have a platform-specific interface (something on Windows only, for instance).

How can I specify (in the xml, or programmatically) that this service should only be added to the Lookup if the platform is Windows? >

In general there are three ways to achieve this.

How shall I write an extension point for my module?

Q: I have more modules one of them providing the core functionality and few more that wish to extend it. What is the right way to do it? How does the Netbeans platform declare such extension point?

Start with declaring an extension interface in your core module and put it into the module's public packages. Imagine for example that the core module is in JAR file org-my-netbeans-coremodule.jar and already contains in manifests line like OpenIDE-Module: org.my.netbeans.coremodule/1 and wants to display various tips of the day provided by other modules and thus defines:

 

package org.my.netbeans.coremodule;

public interface TipsOfTheDayProvider {
    public String provideTipOfTheDay ();
}

And in its manifest adds line OpenIDE-Module-Public-Packages: org.my.netbeans.coremodule.* to specify that this package contains exported API and shall be accessible to other modules.

When the core module is about to display the tip of the day it can ask the system for all registered instances of the TipsOfTheDayProvider, randomly select one of them:


import java.util.Collection;
import java.util.Collections;
import org.openide.util.Lookup;

Lookup.Result result = Lookup.getDefault ().lookup (new Lookup.Template (TipsOfTheDayProvider.class));
Collection c = result.allInstances ();
Collections.shuffle (c);
TipsOfTheDayProvider selected = (TipsOfTheDayProvider)c.iterator ().next ();

and then display the tip. Simple, trivial, just by the usage of Lookup interface once creates a registry that other modules can enhance. But such enhancing of course requires work on the other side. Each module that would like to register its TipsOfTheDayProvider needs to depend on the core module - add OpenIDE-Module-Module-Dependencies: org.my.netbeans.coremodule/1 into its manifest and write a class with its own implementation of the provider:


package org.my.netbeans.extramodule;

class ExtraTip implements TipsOfTheDayProvider {
    public String provideTipOfTheDay () {
        return "Do you know that in order to write extension point you should use Lookup?";
    }
}

Then, the only necessary thing is to register such class by using the J2SE standard into plain text file META-INF/services/org.my.netbeans.coremodule.TipsOfTheDayProvider in the module JAR containing just one line:

org.my.netbeans.extramodule.ExtraTip

and your modules are now ready to communicate using your own extension point.


How to use Window System?

Window System API is used to display and control application GUI: Main window, frames, components.

General Use cases can be read on the external page. Here is a small howto for simple things that may be found useful:

How to create a '.settings' file for a TopComponent?

Either write it by hand (not that hard if you copy other file and tweak it to match your TC), or start the IDE, instantiate the TC somehow (You have a "Window->Show My TC", right? ), copy the file that gets created in $userdir/config/Windows2Local/Component and cleanup the serialdata section - replace it with proper "<instance class='..." /> tag.

How to make a TopComponentGroup?

Q: I'm trying to make a TopComponentGroup. I've just read http://ui.netbeans.org/docs/ui/ws/ws_spec.html#3.9 I want to make a group that uses the first invocation strategy. That is, I want the group to open/close when I activate a certain subclass of TopComponent. Say, for example, I have a FooTopComponent, and when it's active, I want to open a FooPropertySheetComponent, docked in a mode on the right-hand side. I know I have to:
  1. declare the group in the layer file (Windows2/Groups)
  2. have code for opening the group
  3. have code for closing the group
I think I do #2 in FooTopComponent.componentActivated() and #3 in FooTopComponent.componentDeactivated(). Is that right?

A:Yes it is correct way. You can check simple test module. First you must get TopComponentGroup instance using find method then call TopComponentGroup.open()/close(). Here is the code in your componentDeactivated method:
   protected void componentDeactivated ()
   {
       // close window group containing propsheet, but only if we're
       // selecting a different kind of TC in the same mode
       boolean closeGroup = true;
       Mode curMode = WindowManager.getDefault().findMode(this);
       TopComponent selected = curMode.getSelectedTopComponent();
       if (selected != null && selected instanceof FooTopComponent)
           closeGroup = false;
             if (closeGroup)
       {
           TopComponentGroup group = WindowManager.getDefault().findTopComponentGroup(TC_GROUP);
           if (group != null)
           {
               group.close();
           }
       }
   }