Platinum Partner
netbeans

Tip: Reusing a Visual Library Popup in the NetBeans Platform Toolbar

A question asked by Martin Has in my blog: "How to migrate visual library PopupMenu actions to the NetBeans Platform toolbar?" I asked Visual Library author David Kaspar this question today and he gave me all the info I needed.

To follow along with the instructions below, download this sample on Kenai:

http://kenai.com/projects/nb-visualanagram/sources/subversion/show/mf_training

We will start with the following section in the "WordGraph" class. This is where a popup menu action is defined. And that's what we'd like to be able to invoke from a menu item in the menu bar AS WELL AS from the same place where it is currently found, i.e., within the scene in the TopComponent:

sc.getActions().addAction(ActionFactory.createPopupMenuAction(new PopupMenuProvider() {
    @Override
    public JPopupMenu getPopupMenu(Widget widget, Point localLocation) {
        JPopupMenu m = new JPopupMenu();
        m.add(new AbstractAction("Zoom out") {
@Override
            public void actionPerformed(ActionEvent e) {
                sc.setZoomFactor(sc.getZoomFactor() * 0.8);
            }
        });
        return m;
    }
}));

Change the above to the following:

sc.getActions().addAction(ActionFactory.createPopupMenuAction(new PopupMenuProvider() {
    @Override
    public JPopupMenu getPopupMenu(Widget widget, Point localLocation) {
        Action[] actions = new Action[]{SystemAction.get(ZoomOutAction.class)};
        JPopupMenu m = Utilities.actionsToPopup(actions, sc.getView());
        return m;
    }
}));

Now, in line 4 above, you're referring to an action classcalled "ZoomOutAction" which, in line 5, is turned into a popup menu via a Utilities class provided by the NetBeans Utilities API (org.openide.util.Utilities).

Here's the definition of that action class, i.e., ZoomOutAction. Note that we cannot use an ActionListener class, which would be the ideal approach from 6.7 onwards, since the Utilities.actionsToPopup can only take an Action subclass, hence I've chosen CallableSystemAction:

import org.netbeans.api.visual.widget.Scene;
import org.openide.util.HelpCtx;
import org.openide.util.actions.CallableSystemAction;
import org.openide.windows.WindowManager;

public class ZoomOutAction extends CallableSystemAction {

    private Scene sc = null;

    public ZoomOutAction() {
        WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
@Override
            public void run() {
                sc = WindowManager.getDefault().findTopComponent("GraphTopComponent").getLookup().lookup(Scene.class);
            }
        });
    }

    @Override
    public void performAction() {
        sc.setZoomFactor(sc.getZoomFactor() * 0.8);
    }

    @Override
    public String getName() {
        return "Zoom Out";
    }

    @Override
    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }
   
}

Note that in the constructor we're getting the "Scene" object from the context of the GraphTopComponent. If we were to try to get it from the global lookup, we'd have a problem because the GraphTopComponent isn't necessarily active. And it is the active TopComponent that populates the global lookup. Especially since we'll be invoking the action from the menu bar, the GraphTopComponent will possibly not be active (since a different TopComponent could be active when we choose this menu item), hence we need to get the Scene object directly from the GraphTopComponent.

To make the above possible, we need to add the line below to the the GraphTopComponent constructor, so that the Scene object is added to the GraphTopComponent lookup:

associateLookup(Lookups.singleton(sc));

Finally, we need to register the CallableSystemAction in the layer:

<folder name="Menu">
<folder name="File">
<file name="org-netbeans-edu-matfyz09-ZoomOutAction.instance"/>
</folder>
</folder>

And now the same menu item that you invoke from the popup within the TopComponent...

...can also be invoked from a menu item in the main menu bar:

 

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}