NB: How do I create an action which can be invoked by a macro?

Use @EditorActionRegistration!

@NbBundle.Messages({ "CTL_MyAction=Let's go", "macro-name=Let's go" })
@EditorActionRegistration(
	name = "macro-name", 
	mimeType = "text/x-java", 
	menuPath = "Source", menuPosition = 0, menuText = "#CTL_MyAction")
public class MyAction extends org.netbeans.editor.BaseAction {
 //...
}

Now your action can be invoked by a macro using its macroname (the name attribute in the @EditorActionRegistration-Annotation) and even recorded by the macro recorder.

[1] http://wiki.netbeans.org/DevFaqAddMacroableAction

NB: How to create toggle-able action for toolbars/menu bars?

For a new NetBeans plugin of mine I was in the need to create a toggle-able action for the toolbar/menu. It took a while, but after some research I found the gem in the NetBeans API: org.openide.util.actions.BooleanStateAction [1]. Easy to use, once you know of its existence. I documented it at [2].

Using it you can create toolbar buttons like this, which behave like JToggleButtons: 2016-06-03_00h07_56.png

Bonus: If you like to create a toggle-able Action, which is bound to a boolean value from a property file (/configuration file) then org.openide.awt.Actions.checkbox  [3] is the solution. An example can be found at [4]

[1] http://bits.netbeans.org/dev/javadoc/org-openide-util-ui/org/openide/util/actions/BooleanStateAction.html
[2] http://wiki.netbeans.org/DevFaqToggleActionAddToEditorToolbar
[3] http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/Actions.html#checkbox-java.lang.String-java.lang.String-java.lang.String-java.lang.String-boolean-
[4] http://wiki.netbeans.org/DevFaqCheckableActionPreferenceOption

NB: How to create a context-aware submenu

Last time I blogged about “How create a context sensitive action with a submenu in the project-view?” [1].  Now there was an additional requirement to be fulfilled: The submenu should be only enabled, when exactly two project nodes are selected. Only if this condition is true, the submenu items should be displayed.

Thanks to the help of Jean-Marc Borer a solution can be provided too.

@ActionID(
        category = "MyActions",
        id = "de.markiewb.netbeans.sample.ContextAwarePopupAction"
)
@ActionRegistration(
        displayName = "#CTL_ContextAwarePopupAction", lazy = false
)
@ActionReferences({
    @ActionReference(path = "Projects/Actions")
})
@Messages("CTL_ContextAwarePopupAction=I am a context-aware submenu")
public final class ContextAwarePopupAction extends AbstractAction implements ActionListener, Presenter.Popup {

    private final Lookup.Result<Project> result;
    private final transient LookupListener lookupListener;

    public ContextAwarePopupAction() {
        putValue(NAME, Bundle.CTL_ContextAwarePopupAction());
        //disabled by default - at loading time
        setEnabled(false);
        //create an action, which is only enabled when exactly 2 projects are selected
        result = Utilities.actionsGlobalContext().lookupResult(Project.class);
        this.lookupListener = new LookupListener() {

            @Override
            public void resultChanged(LookupEvent ev) {
                final Runnable runnable = new Runnable() {

                    @Override
                    public void run() {
                        int s = result.allInstances().size();
                        ContextAwarePopupAction.this.setEnabled(s == 2);
                    }
                };
                // to make sure that it will be executed on EDT
                if (EventQueue.isDispatchThread()) {
                    runnable.run();
                } else {
                    SwingUtilities.invokeLater(runnable);
                }
            }
        };
        result.addLookupListener(WeakListeners.create(LookupListener.class, this.lookupListener, result));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //NOP
    }

    @Override
    public JMenuItem getPopupPresenter() {
        JMenu main = new JMenu(this);
        List<? extends Action> actionsForPath = Utilities.actionsForPath("Actions/MyActions/SubActions");
        for (Action action : actionsForPath) {
            main.add(action);
        }
        return main;
    }
}

The most important part of the popup action is to emulate a context-aware action using a lookup listener.

2015-09-13_21h36_02

The updated sample code can be found at https://github.com/markiewb/nb-api-samples/tree/master/SubmenuWithContextSensitiveAction. The entry of the offical developer FAQ at http://wiki.netbeans.org/DevFaqActionNodePopupSubmenu has also been updated.

[1] https://benkiew.wordpress.com/2015/09/01/nb-how-to-create-a-context-sensitive-action-within-a-submenu/

 

NB: How to create a context sensitive action within a submenu

Today somebody asked “how create a context sensitive action with a submenu in the project-view?” in the NetBeans mailing list. So I figured it out and I like to document it using this post.

First here is the action for the submenu. The action is registered to the project context menu. It uses the Presenter.Popup interface to register itself as a submenu. In the getPopupPresenter() method the submenu is assembled via Utilities.actionsForPath.

@ActionID(
        category = "MyActions",
        id = "de.markiewb.netbeans.sample.PopupAction"
)
@ActionRegistration(
        displayName = "#CTL_PopupAction", lazy = false
)
@ActionReferences({
    @ActionReference(path = "Projects/Actions")
})
@Messages("CTL_PopupAction=I am a submenu")
public final class PopupAction extends AbstractAction implements ActionListener, Presenter.Popup {

    @Override
    public void actionPerformed(ActionEvent e) {
        //NOP
    }

    @Override
    public JMenuItem getPopupPresenter() {
        JMenu main = new JMenu(Bundle.CTL_PopupAction());
        List<? extends Action> actionsForPath = Utilities.actionsForPath("Actions/MyActions/SubActions");
        for (Action action : actionsForPath) {
            main.add(action);
        }
        return main;
    }
}

In the previous code snippet Utilities.actionsForPath has been used to resolve action(s) at Actions/MyActions/SubActions. Here is a context sensitive action, which is registered at this location.

@ActionID(
        category = "MyActions/SubActions",
        id = "de.markiewb.netbeans.sample.HelloProjectsAction"
)
@ActionRegistration(
        displayName = "#CTL_HelloProjectsAction"
)
@Messages("CTL_HelloProjectsAction=HelloProjects...")
public final class HelloProjectsAction implements ActionListener {

    private final List context;

    public HelloProjectsAction(List context) {
        this.context = context;
    }

    @Override
    public void actionPerformed(ActionEvent ev) {
        JOptionPane.showMessageDialog(null, context.size() + " projects selected: " + context);
    }
}

The result:
SubmenuWithContextSenstiveAction

The complete sample code can be found at https://github.com/markiewb/nb-api-samples/tree/master/SubmenuWithContextSensitiveAction. I will also add this documentation to the offical developer FAQ at http://wiki.netbeans.org/DevFaqActionNodePopupSubmenu

Happy coding!

Update: The second part of this post can be found at https://benkiew.wordpress.com/2015/09/13/nb-how-to-create-a-context-aware-submenu/

NB platform: Catching missing resources at compile-time using @StaticResource

When you develop a NetBeans platform application sometimes you like to refer to existing resource files like images.

Therefor you have to hard-code the path into your sources in a string literal. Normally you would notice a wrong path at runtime because of a FileNotFoundException – not very professional.

But wait! Use the org.netbeans.api.annotations.common.StaticResource-annotation from the Common Annotations module (/org.netbeans.api:org-netbeans-api-annotations-common) instead. Backed by an annotation processor NetBeans will check whether the path is correct at compile-time. This is pretty cool.

What do you get? NetBeans shows missing resources in the editor, in the “Action Items”-view and even the build will fail.

2015-02-21_18h33_57

[1] http://bits.netbeans.org/8.0/javadoc/org-netbeans-api-annotations-common/org/netbeans/api/annotations/common/StaticResource.html

Improved Maven-based NetBeans Platform Application Development using JRebel

Some months ago I already blogged about how to tweak the pom.xml of your Maven-based NetBeans platform application so that you can use JRebel to reload your changes. [1] This process has been simplified in the meantime. Thanks to Peter Hansson for letting me know. Steps:

  • Install the JRebel NetBeans IDE Plugin (from the Plugin Center or from your IDE)
  • Make sure “Compile on Save” is enabled for your project.
  • Make sure the “Enable/Disable JRebel” toolbar button is checked.
  • Generate a rebel.xml file: In the context menu of the project choose “Open JRebel panel” and check the checkbox next to your project in the JRebel Panel.
  • Alter the properties section of the pom.xml like this
        <!-- for JRebel 5.x / JRebel 6 Legacy Client -->
        <properties>
            <!--...-->
            <netbeans.run.params.ide/>
            <netbeans.run.params>-J-javaagent:"${current.jrebel.agent.path}" -J-Drebel.log=true ${netbeans.run.params.ide}</netbeans.run.params>
        </properties>
    
        <!-- for JRebel 6.x (Non-Legacy Client)-->
        <properties>
            <!--...-->
            <netbeans.run.params.ide/>
            <netbeans.run.params>-J-Xbootclasspath/p:C:\temp\rebelboot.jar -J-javaagent:"${current.jrebel.agent.path}" -J-Drebel.log=true ${netbeans.run.params.ide}</netbeans.run.params>
        </properties>
    

    The NEW and COOL thing is that you do not have to bother yourself with the path of the JRebel jar file anymore. The JRebel NetBeans IDE plugin sets the path to the JRebel jar from your IDE into the Maven property “current.jrebel.agent.path” and you can reuse it in your pom.xml. Now there will be no hardcoded paths anymore, when you check-in your pom.xml to SCM – except the JRebel6 bootclasspath edge-case.

  • run the module – the application with your module and JRebel should start up
  • make changes to your classes and JRebel will pick them up

Here a screenshot to illustrate the previous steps: 2014-09-03_23h34_17 Tested with NetBeans 8.0, JRebel NetBeans IDE Plugin 5.6.2 [1] https://benkiew.wordpress.com/2013/10/27/maven-based-netbeans-platform-development-with-jrebel-6-minor-update/

How to convert an ANT-based NetBeans Module to a Maven-based NetBeans Module

I am currently converting some of my ANT-based NetBeans Modules to Maven-based ones. I didn’t found a step-by-step migration list, so I decided to create one and to share it with you. The following list was created while converting a simple plugin with less than 20 classes, so the migration steps of large projects might vary. But you should get the basic idea.

  • create a new maven based NBM using the “New Project”-wizard (to reuse a working configuration)
  • copy the folder src and pom.xml to the old project
  • in pom.xml
    • define a groupId
    • set the name from OpenIDE-Module-Name entry in Bundle.properties
    • set the artifactid from OpenIDE-Module entry in MANIFEST.MF
    • set the version from OpenIDE-Module-Specification-Version entry in MANIFEST.MF
  • remove the line with OpenIDE-Module-Specification-Version entry from MANIFEST.MF
  • remove the line with OpenIDE-Module entry from MANIFEST.MF
  • remove nbproject/genfiles.properties
  • remove nbproject/platform.properties
  • remove nbproject/build-impl.xml
  • remove build.xml
  • move manifest.mf to folder src/main/nbm
  • move your sources (*.java) to src/main/java (or src/test/java) (GIT is very useful here, the commit history isn’t lost)
  • move your resources (not *.java) to src/main/resources (or src/test/resources) (especially Bundle.properties)
  • add dependencies (the most annoying part)
    • foreach dependency entry (code-name-base) in nbproject/project.xml add a dependency via the “Add dependency” dialog OR add a dependency manually to pom.xml

    For example use

    <dependency>
      <groupId>org.netbeans.api</groupId>
      <artifactId>org-netbeans-modules-projectapi</artifactId>
      <version>RELEASE73</version>
    </dependency>

    for

    <dependency>
      <code-name-base>org.netbeans.modules.projectapi</code-name-base>
      <build-prerequisite/>
      <compile-dependency/>
      <run-dependency>
          <release-version>1</release-version>
          <specification-version>1.46.1</specification-version>
      </run-dependency>
    </dependency>

    (!) Note that the dots in the dependency name have to replaced by a dashes

  • add test dependenciesFor example use
    <dependency>
        <groupId>org.netbeans.api</groupId>
        <artifactId>org-netbeans-libs-junit4</artifactId>
        <version>RELEASE73</version>
        <scope>test</scope>
    </dependency>

    for

    <test-dependencies>
        <test-type>
            <name>unit</name>
            <test-dependency>
                <code-name-base>org.netbeans.libs.junit4</code-name-base>
                <compile-dependency/>
            </test-dependency>
        </test-type>
    </test-dependencies>

There is still more to do. Like to configure export packages, signing, homepage and so one. Most of these configuration settings defined in the original project.properties have a counterpart in the plugin configuration of the nbm-maven-plugin. See the detailed goal documentation at http://mojo.codehaus.org/nbm-maven/nbm-maven-plugin/nbm-mojo.html

But your mavenized plugin should start at least now.

PS: The whole process is worth a plugin itself.  Any volunteer?