Changing a Node from its Popup Menu

I learnt some interesting things with Børre Dalhaug today. Look at the screenshot below:

When a submenu is selected, the display name of the Node is automatically updated to the text in the selected submenu:

I couldn't figure out how to use the new Actions.* factories for the above scenario. Instead, it's done like this:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import net.dalhaug.borre.context691.domainobjects.IDrummer;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.actions.CookieAction;
import org.openide.util.actions.Presenter;

public final class ChangeDrumAction extends CookieAction 
    implements Presenter.Popup, ActionListener {

    private static final String PROP_KEY = "";
    private IDrummer context = null;

    public JMenuItem getPopupPresenter() {
        JMenu changeDrumKitMenu = new JMenu("Change " + context.getDrumKit());
        changeDrumKitMenu.setIcon(ImageUtilities.loadImageIcon("net/dalhaug/icons/Arrow.png", false));
        for (String string : context.getAvailableDrumsets()) {
            JMenuItem subMenu = new JMenuItem(string);
            //Create a client property on the JMenuItem:
            subMenu.putClientProperty(PROP_KEY, string);
        return changeDrumKitMenu;
    //The Action that will be invoked on the submenus:
    public void actionPerformed(ActionEvent ev) {
        if (ev.getSource() instanceof JMenuItem) {
            JMenuItem item = (JMenuItem) ev.getSource();
            //Retrieve from the client property on the JMenuItem:
            String drumKit = (String) item.getClientProperty(PROP_KEY);

    protected boolean enable(Node[] nodes) {
        if (nodes[0].getLookup().lookup(IDrummer.class)!=null){
            context = nodes[0].getLookup().lookup(IDrummer.class);
            return true;
        return false;
    protected int mode() {
        return CookieAction.MODE_EXACTLY_ONE;

    protected Class<?>[] cookieClasses() {
        return new Class[]{IDrummer.class};

    //Not used:
    public String getName() {return null;}
    //Not used:
    @Override protected void performAction(Node[] nodes) {}

    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;


The above is registered as follows:

<folder name="Actions">
    <folder name="OSC">
        <file name="net-dalhaug-ChangeDrumAction.instance"/>

And here's the Node:

public class DrummerNode extends AbstractNode implements PropertyChangeListener {

    private final IDrummer drummer;

    public DrummerNode(IDrummer drummer) {
        super(Children.LEAF, Lookups.singleton(drummer));
        this.drummer = drummer;
        setName(drummer.getName() + " plays " + drummer.getDrumKit());

    public Image getIcon(int type) {
        return ImageUtilities.loadImage("net/dalhaug/borre/context691/Drum24.png");

    public Action[] getActions(boolean context) {
        List<? extends Action> oscActions = Utilities.actionsForPath("Actions/OSC");
        return oscActions.toArray(new Action[oscActions.size()]);

    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(Drummer.PROP_DRUMKIT)) {
            setDisplayName(drummer.getName() + " plays " + drummer.getDrumKit());

You cannot use Actions.* factories for this since it is inherently nonlazy, but you should be able to use @ActionRegistration on it anyway. (By implementing Presenter.Popup you magically indicate that you do not want to use a factory.)

Posted by Jesse Glick on November 08, 2011 at 10:51 AM PST #

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.


« August 2015