NetBeans declarative Action registration vs. Node popup menu
The "New Action" Wizard in NetBeans 7.0 generates a class which implements the ActionListener
interface and has several annotations. These annotations place references to this action in the Toolbars/Menus specified in the Wizard. Most of this is explained in the NetBeans wiki and works as expected.
The problem arises when I want to add such an action to the context menu of a Node. Exposing Actions there means you have to return concrete instances of your actions from the Node.getActions(..) method. The missing piece here is that I have an ActionListener
with some fancy annotations, but instead I need an Action
instance which is backed by this listener. When trying to fill this gap I stumbled upon a blog post by Geertjan, which seems somehow related and led to an static method I added to my ActionListener
:
public static Action findAction() throws Exception {
final FileObject fo = FileUtil.getConfigFile(
"Actions/Tools/foo开发者_如何转开发-bar-Action.instance");
final DataObject dob = DataObject.find(fo);
final InstanceCookie ic = dob.getLookup().lookup(InstanceCookie.class);
if (ic != null) {
final Object instance = ic.instanceCreate();
if (instance instanceof Action) {
return (Action) instance;
}
}
return null;
}
While this works, it surely isn't the most beautiful piece of code with all that going through the file system API and that ugly action name string constant. It seems very brittle to me.
So I'd like to know what is the preferred way to get my wizard-generated action into a node's context menu? If that matters I'd like to mention that my action is context aware (so it needs a specific interface in the lookup to be enabled).
There exists a utility method in org.openide.util.Utilities called actionsForPath(String path). Using this, I would replace the above code with something like the following in the Node:
import org.openide.util.Utilities;
...
public static final String FOO_CLASS_PATH = "Actions/Tools";
...
@Override
public Action[] getActions( boolean context ) {
List<? extends Action> actions = Utilities.actionsForPath( FOO_CLASS_PATH );
return actions.toArray( new Action[actions.size()] );
}
This will return all of the actions registered for (in this case) Tools. I like to place node specific Actions in a category for the specific Node using the @ActionID or @ActionReferences annotations on the Action class.
To specify only the one specific Action instance, such as for getPreferredAction(), include the full instance path and return only the first element of the List.
精彩评论