X

Geertjan's Blog

  • March 3, 2013

Creating a Customized OpenAction

Geertjan Wielenga
Product Manager

The question of the day comes from Michael Bishop who, in a follow up to yesterday's blog entry, doesn't simply want the display text of the OpenAction to be "Open". He wants it to show something about the context, e.g., "Open Joe", where Joe is the name of the underlying object.

The key to solving this problem is described in Dynamically Changing the Display Names of Menus and Popups.

And so here's the code, i.e., remove the NetBeans Platform OpenAction and create your own instead:

import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import org.netbeans.api.actions.Openable;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.Utilities;
import org.openide.util.WeakListeners;

@ActionID(
        category = "PersonActions",
        id = "org.person.viewer.PersonOpenAction")
@ActionRegistration(
        lazy = false,
        displayName = "NOT-USED")
@ActionReference(path = "Menu/File", position = 1300)
public final class PersonOpenAction extends AbstractAction implements LookupListener {

    private Lookup.Result<PersonNode> personNodeResult;
    private Openable context;

    public PersonOpenAction() {
        super("Open Person");
        personNodeResult = Utilities.actionsGlobalContext().lookupResult(PersonNode.class);
        personNodeResult.addLookupListener(
                WeakListeners.create(LookupListener.class, this, personNodeResult));
        resultChanged(new LookupEvent(personNodeResult));
    }

    @Override
    public void actionPerformed(ActionEvent ev) {
        context.open();
    }

    @Override
    public void resultChanged(LookupEvent le) {
        Collection<? extends PersonNode> p = personNodeResult.allInstances();
        if (p.size() == 1) {
            PersonNode currentPersonNode = p.iterator().next();
            context = currentPersonNode.getLookup().lookup(Openable.class);
            String displayText = "Open Person: " + currentPersonNode.getDisplayName();
            putValue("popupText", displayText);
            putValue("menuText", displayText);
        }
    }

    @Override
    public boolean isEnabled() {
        return context!=null ? true : false;
    }

}

Above, the assumption is that there's an Openable in the Node Lookup. If
you're using OpenCookie or something different instead, change the code
above accordingly. Secondly, above the display name of the Node is used
to set the display text of the popup and menu. Of course, instead of
that, you could look in the Lookup of the Node for your Object, e.g.,
Person, and then get some value from that Object.

Display the Action above on the Node as follows (and it is automatically available in the menu bar thanks to the @ActionReference annotation above):

@Override
public Action[] getActions(boolean context) {
    List<? extends Action> personActions = Utilities.actionsForPath("Actions/PersonActions");
    return personActions.toArray(new Action[personActions.size()]);
//        return new Action[]{SystemAction.get(OpenAction.class)};
}

Join the discussion

Comments ( 7 )
  • Michael Bishop Sunday, March 3, 2013

    Very interesting, thanks so much! I'd been trying unsuccessfully to change the text with putValue(Action.NAME, displayText). Where did you derive the menuText and popupText keys? I can't find a reference to them in the JDK docs. Are these keys that the NetBeans platform has adopted?


  • Geertjan Sunday, March 3, 2013
  • Jean-Marc Borer Monday, March 4, 2013

    Hi Geertjan,

    Seeing this part of the code:

    personNodeResult = Utilities.actionsGlobalContext().lookupResult(PersonNode.class);

    personNodeResult.addLookupListener(

    WeakListeners.create(LookupListener.class, this, personNodeResult));

    resultChanged(new LookupEvent(personNodeResult));

    makes me think about an interesting topic about the WeakListeners class provided by Netbeans. You could explain the purpose of the lines above to newbies and if this it the "state of the art" way to work with lookups or not (or when to use WeakListeners and when not).

    Cheers,

    Jean-Marc


  • Jean-Marc Borer Monday, March 4, 2013

    By the way, I remember from some docuement that you are supposed to invoke allInstance() method on the lookup (or someting like this), to somehow start listening to changes events. Is this still true?


  • Geertjan Monday, March 4, 2013

    Lots of info about WeakListeners in the javadoc:

    http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/WeakListeners.html

    About your second question, no that's not needed anymore.


  • Atomix Friday, July 19, 2013

    Hi Geertjan,

    I'm trying to make an Multiview XML Editor with ability to use Palette drag and drop function. The problem is the Top Component's lookup should be associate with a PaletteSupport and it seems impossible to get add thing to other TopComponent's lookup on the fly.

    Is there anyway around this? Thank a lot.


  • Geertjan Saturday, July 20, 2013

    Hi Atomix,

    I typed "multview palette geertjan" into Google and found this:

    https://blogs.oracle.com/geertjan/entry/adding_a_palette_to_a1

    Hope it helps,

    Gj


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