Geertjan's Blog

  • October 26, 2009

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

Geertjan Wielenga
Product Manager
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"/>
<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"/>

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

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.

Join the discussion

Comments ( 7 )
  • Jesse Glick Monday, October 26, 2009

    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.

  • Geertjan Wielenga Monday, October 26, 2009

    Thanks for this info!

  • Fabrizio Giudici Monday, October 26, 2009

    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?

  • Jesse Glick Monday, October 26, 2009

    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.\*.

  • Fabrizio Giudici Monday, October 26, 2009

    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.

  • Jesse Glick Monday, October 26, 2009

    This seems to work:


    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.

  • Andrew May Wednesday, November 18, 2009

    Got an issue where my action extends SystemAction and implements Presenter.Toolbar but always tests false for 'item instanceof Presenter.Toolbar'? The action is defined within Actions/ and registered to my Toolbar using a .shadow link, and later retrieved within my Toolbar class using Utilities.actionsForPath. Also tried Lookups.forPath(path) etc etc but with the same result. Anyone else come across this?

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.