Download NetBeans!

20091026 Monday October 26, 2009

Calling an Action in the Layer from a Button in a Local Toolbar

I have a window with a toolbar containing a button:

When I click the button, an action that is registered in the layer is invoked. That's great, means that I can integrate my standard Swing components with the NetBeans System FileSystem. Plus that lets me empower the action declaratively with, for example, asynchronous processing by adding a single attribute to the related layer entry (see elsewhere in this blog for this 6.8 enhancement).

How is all this possible?

Well, this is how the action is registered in the layer:

<folder name="Actions">
    <folder name="Bla">
        <file name="org-demo-globloc-GlobLocAction.instance">
            <attr name="delegate" newvalue="org.demo.globloc.GlobLocAction"/>
            <attr name="displayName" bundlevalue="org.demo.globloc.Bundle#CTL_GlobLocAction"/>
            <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-globloc-GlobLocAction.shadow">
            <attr name="originalFile" stringvalue="Actions/Bla/org-demo-globloc-GlobLocAction.instance"/>
            <attr name="position" intvalue="0"/>
        </file>
    </folder>
</folder>

Take note of the bits in bold above. Now, this is in the button's action performed:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

   ActionListener al = Lookups.forPath("/Actions/Bla/").lookup(ActionListener.class);
   al.actionPerformed(evt);

}

Here the scenario is very simple, since we know exactly where the action listener is registered and that there is only one file registered in the folder.

More complex scenarios, where you have separators as well as other actions registered in the same folder, require you to do some testing of the instances. See Layer-Based Popup Menus in TopComponents and the other references you find there for further details, if needed.

Also see this discussion from today, which includes code from Fabrizio.

In other news. What's the deal with OSGi and the NetBeans Platform? Watch this brand new screencast for all the details.

Oct 26 2009, 09:08:31 AM PDT Permalink

Trackback URL: http://blogs.sun.com/geertjan/entry/calling_an_action_in_the
Comments:

Probably better to use Utilities.actionsForPath. Pass a folder and you get some Action's in layer order (or null meaning a JSeparator has been requested). You can then make JButton's from the Action's (e.g. use Actions.connect). This is preferable to looking up ActionListener since a full Action can set an icon, disable itself, etc. This style is more idiomatic, more general, and may actually be simpler than the code you quote (which omits JButton construction and wiring).

Also, do not the Actions/ folder for GUI registrations. Actions/ is intended only for definitions of available actions. To register a particular action in the GUI, use a .shadow to link to it from some other folder, e.g. MyToolbar/ in this case, or whatever makes sense.

Posted by Jesse Glick on October 26, 2009 at 10:04 AM PDT #

Thanks for this info!

Posted by Geertjan Wielenga on October 26, 2009 at 10:24 AM PDT #

But what if you need to (well, plan to) add further stuff in the Toolbar? For instance, drop down menus, or even static components (labels). Utilities only returns Actions, so it would be impossible to get other stuff.

So, I look up for any Object, and conditionally tread the stuff inside (using Action in place of ActionListener). Is this ok?

Posted by Fabrizio Giudici on October 26, 2009 at 01:59 PM PDT #

If you want to support actions with custom presenters when using actionsForPath, simply check for instanceof Presenter.Toolbar, using JButton + Actions.connect as a fallback if not implemented.

Might make sense to have a utility API somewhere (Actions?) which would create a JToolBar or JMenu based on a folder path, considering JSeparator and Presenter.*.

Posted by Jesse Glick on October 26, 2009 at 02:07 PM PDT #

A specific API would definitely help - I'd really like to see a simple call which creates a component ready to be used and put into a UI. "Local" toolbars are quite common in desktop apps.

Posted by Fabrizio Giudici on October 26, 2009 at 03:25 PM PDT #

This seems to work:

https://hg.kenai.com/hg/sqe~trunk/raw-file/tip/core.ui.components/src/org/nbheaven/sqe/core/ui/components/toolbar/ToolBarFromLayer.java

If it turns out that a bunch of different apps can reuse this utility class unmodified, file an API review and it could be added to the Platform.

Posted by Jesse Glick on October 26, 2009 at 05:55 PM PDT #

Post a Comment:

Name:
E-Mail:
URL:

Your Comment:

HTML Syntax: NOT allowed