Download NetBeans!

20081202 Tuesday December 02, 2008

From ActionListener to CallableSystemAction

In 6.5, when you create an "Always Enabled" action, the "New Action" wizard gives you this Java code:

package org.demo.module;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public final class SomeAction implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        // TODO implement action body
    }
}

Very nice... because you're using plain old Java code. The ActionListener is one of the JDK's classes, unlike the Action classes that the NetBeans Platform provides. In previous releases, you would get a CallableSystemAction instead, which is one of those NetBeans Platform classes.

To make it possible for the NetBeans Platform to hook the above class into the NetBeans action system, the following entries are added to the layer.xml file, by the same "New Action" wizard that created the above Java class:



<filesystem>
    <folder name="Actions">
        <folder name="Build">
            <file name="org-demo-module-SomeAction.instance">
                <attr name="SystemFileSystem.localizingBundle" stringvalue="org.demo.module.Bundle"/>
                <attr name="delegate" newvalue="org.demo.module.SomeAction"/>
                <attr name="displayName" bundlevalue="org.demo.module.Bundle#CTL_SomeAction"/>
                <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/>
                <attr name="noIconInMenu" boolvalue="false"/>
            </file>
        </folder>
    </folder>
    <folder name="Menu">
        <folder name="File">
            <file name="org-demo-module-SomeAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Build/org-demo-module-SomeAction.instance"/>
                <attr name="position" intvalue="0"/>
            </file>
        </folder>
    </folder>
</filesystem>

Take careful note of the section that is in bold above! There you can see how the ActionListener implementation is hooked into the NetBeans action system. For example, the "instanceCreate" attribute causes a NetBeans Platform action to be created for your ActionListener! So, even though you're using plain old Java, the entries above (generated automatically by the wizard) cause the ActionListener to be treated as a NetBeans Platform class.

However... the NetBeans Platform classes are much more powerful than the ActionListener class. For example, if you use the CallableSystemAction class, you can (in bad pseudo code, any way) do something like this:

@Override
public void setEnabled(boolean enabled) {
    if (hell freezes over){
        enable this menu item
    } else {
        not
    }
}

In other words, the NetBeans Platform action classes provide built-in support for enabling/disabling themselves. Therefore, you're quite likely to want to 'upgrade' your ActionListener to a CallableSystemAction. So, what must one do to transform one's ActionListener into a CallableSystemAction? First, change the class signature so that you're extending "CallableSystemAction", instead of implementing "ActionListener". The Utilities API, which provides the "CallableSystemAction" class, is already set as one of the module's dependencies when you complete the "New Action" wizard, so there are no additional dependencies you need to set. You'll find you need to do something with a bunch of methods that come from the CallableSystemAction class and/or its ancestors.

Next... you need to tweak the layer.xml file so that the bits in bold above are removed. You'll be left with this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
    <folder name="Actions">
        <folder name="Build">
            <file name="org-demo-module-SomeAction.instance"/>
        </folder>
    </folder>
    <folder name="Menu">
        <folder name="File">
            <file name="org-demo-module-SomeAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Build/org-demo-module-SomeAction.instance"/>
                <attr name="position" intvalue="0"/>
            </file>
        </folder>
    </folder>
</filesystem>

Or, if you have the display name in the localizing bundle, you might have this instead:

    <folder name="Actions">
        <folder name="Build">
            <file name="org-demo-module-SomeAction.instance">
                <attr name="SystemFileSystem.localizingBundle" stringvalue="org.demo.module.Bundle"/>
                <attr name="displayName" bundlevalue="org.demo.module.Bundle#CTL_SomeAction"/>
            </file>
        </folder>
    </folder>

And now install your module. Your ActionListener is now a CallableSystemAction.

Dec 02 2008, 09:09:22 AM PST Permalink