The "org.openide.actions.NewAction" provides out-of-the-box UI for creating subnodes. Just add it to the list of Actions defined for your Node (i.e., its context actions) and you're good to go:
public Action[] getActions(boolean context) {
    return new Action[]{SystemAction.get(NewAction.class)};

Read the sources of "NewAction" and you'll find it is a "NodeAction" that is enabled under a very specific condition:

protected boolean enable(Node[] activatedNodes) {
    NewType[] types = getNewTypes();
    return (types.length > 0);

So, if there are one or more "NewType" objects available, then the "NewAction" will be enabled.

Fortunately, the "Node" class gives you a method where you can create "NewType" objects, i.e., "getNewTypes", which returns an array of "NewType" objects. Here's an example:

    "LBL_NewProp=System Property",
    "LBL_NewProp_dialog=Create New Property",
    "MSG_NewProp_dialog_key=New property name:",
    "MSG_NewProp_dialog_value=New property value:"})
public NewType[] getNewTypes() {
    return new NewType[]{new NewType() {
            public String getName() {
                return LBL_NewProp();
            public void create() throws IOException {
                NotifyDescriptor.InputLine msg = new NotifyDescriptor.InputLine(LBL_NewProp_dialog(), MSG_NewProp_dialog_key());
                String key = msg.getInputText();
                if ("".equals(key)) {
                msg = new NotifyDescriptor.InputLine(MSG_NewProp_dialog_value(), MSG_NewProp_dialog_key());
                String value = msg.getInputText();
                System.setProperty(key, value);

Run the above and you see this:

What if you had multiple "NewType" objects in the array, i.e., you want to let the user create different types of subnodes? Then the "NewAction" will automatically have a submenu structure, as shown below:

So, when you combine "NewAction" with "NewType", you have an infrastructure for creating new subnodes.


We may want to make the types of new objects that can be created and the way they are created dependent on what is in the Lookup of the Node having the set of new types (thus, context-sensitive), and register them declaratively (this could be done via iterating over Lookups.forPath("my/type/of/node/newtypes").lookupAll(NewType.class) in getNewTypes() of the node.

However, in this case, as the NewTypes would have no-arg constructors, I don't see how such context could be transferred directly. Would it be necessary to register instances of something resembling

interface NewTypeFactory {
NewType create(Lookup context);

in the layer to obtain this effect?

Posted by Ernest on April 15, 2011 at 03:33 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.


« March 2015