NetBeans IDE 7.3: How to extend the context menu of the members and hierarchy view?

Today i will show you how to extend the context menu of the newly redesigned members and hierarchy view in NetBeans IDE 7.3.

Plugin your action at the following extension points

Navigator/Actions/Members/text/x-java
Navigator/Actions/Hierarchy/text/x-java

and get the TreePathHandle from the Node’s lookup. Easy isn’t it? Please note that these extension points are new in NB IDE 7.3 – see the issues [1] and [2].

This allows the integration of current/future actions which react on
TreePathHandle like

  • toggle method breakpoint (when a method is selected)
  • toggle class breakpoint (when a class is selected)
  • run/debug main method (when a class with a main method is selected)
  • run/debug test (when a class with testmethods is selected or when a testmethod is selected)
  • add as profiling root (when a method is selected)
  • integration of my own “Copy FQN” plugin (i will blog about it next time)

But now a more concrete example:

package de.markiewb.netbeans.sample.extendMembersAndHierarchyView;

import java.util.ArrayList;
import java.util.List;
import static javax.swing.Action.NAME;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import org.netbeans.api.java.source.TreePathHandle;
import org.openide.awt.*;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CookieAction;
import org.openide.util.actions.Presenter;

@ActionID(category = "Edit", id = "de.markiewb.netbeans.sample.extendMembersAndHierarchyView.SampleAction")
@ActionRegistration(displayName = "SampleAction")
@ActionReferences({
    @ActionReference(path = "Navigator/Actions/Members/text/x-java", position = 1150),
    @ActionReference(path = "Navigator/Actions/Hierarchy/text/x-java", position = 1150)
})
public final class SampleAction extends CookieAction implements Presenter.Popup {

    public SampleAction() {
	putValue(NAME, "Hello TreePathHandle(s)");
    }

    @Override
    public String getName() {
	return "Hello TreePathHandle(s)";
    }

    @Override
    public JMenuItem getPopupPresenter() {
	return new JMenuItem(this);
    }

    @Override
    public HelpCtx getHelpCtx() {
	return null;
    }

    @Override
    protected boolean enable(Node[] activatedNodes) {
	//.. use tph from lookup in node
	for (Node node : activatedNodes) {
	    if (null != node.getLookup().lookup(TreePathHandle.class)) {
		return true;
	    };
	}
	return false;
    }

    @Override
    protected int mode() {
	return CookieAction.MODE_ALL;
    }

    @Override
    protected Class[] cookieClasses() {
	return new Class[]{Node.class};
    }

    @Override
    protected void performAction(Node[] nodes) {
	List<TreePathHandle> treePathHandles = new ArrayList<TreePathHandle>();
	for (Node node : nodes) {
	    treePathHandles.add(node.getLookup().lookup(TreePathHandle.class));
	}
	//show all treePathHandles
	JOptionPane.showMessageDialog(null, "Hello\n" + treePathHandles);
    }
}

The result:

example

The full sample project is available at [3]

[1] http://netbeans.org/bugzilla/show_bug.cgi?id=220057
[2] http://netbeans.org/bugzilla/show_bug.cgi?id=224499
[3] https://github.com/markiewb/nb-api-samples/tree/master/ExtendMembersAndHierarchyView
[4] http://wiki.netbeans.org/DevFaqAddActionToMembersOrHierarchyView

NetBeans: How to create a context aware action with an icon for the context menu

Here a small sample how to create a context aware action with icons for a NetBeans Platform RCP application or even the NB IDE. You may wonder and questions like “Why the heck he is doing this” or “Why he won’t use the standard action wizard?” may pop up.

Assigning icons to actions is easy. BUT the icons do will not be displayed in the context menu (by default). It is possible but not best practice in NB RCP. Keep in mind that icons in menus are not supported for MacOS. So use it wisely.

The important points are:

  • extend from AbstractAction to get access to putValue (you loose the standard context aware features, so you have to implement them yourself via keeping a proxy to the global lookup and enabling the action depending on the content of the lookup)
  • implement Presenter.Popup and return a JMenuItem instance for the current action (see [1], [2])
  • set the icon via putValue(javax.swing.Action.SMALL_ICON, ...)
package de.markiewb.netbeans.sample.contextmenu;

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.SMALL_ICON;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import org.netbeans.api.annotations.common.StaticResource;
import org.netbeans.api.project.Project;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;

@ActionID(
        category = "Build",
        id = "de.markiewb.netbeans.sample.contextmenu.HelloIconAction")
@ActionReferences({
    @ActionReference(path = "Menu/File", position = 0),
    @ActionReference(path = "Loaders/Languages/Actions", position = 0),
    @ActionReference(path="Projects/Actions")
})
@ActionRegistration(
        displayName = "#CTL_HelloIconAction")

@Messages("CTL_HelloIconAction=Hello Icon Action")
public final class HelloIconAction extends AbstractAction implements Presenter.Popup {

    @StaticResource
    private static final String ICON = "de/markiewb/netbeans/sample/contextmenu/sample.gif";
    private static final long serialVersionUID = 1L;
    private final Lookup context;

    public HelloIconAction() {
        context = Utilities.actionsGlobalContext();
        putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON, false));
        putValue(NAME, Bundle.CTL_HelloIconAction());
    }

    @Override
    public boolean isEnabled() {
        return null != context.lookup(Project.class);
    }

    @Override
    public void actionPerformed(ActionEvent ev) {
        JOptionPane.showMessageDialog(null, "Hello colorful project.\n" + context.lookup(Project.class).toString());
    }

    @Override
    public JMenuItem getPopupPresenter() {
        return new JMenuItem(this);
    }
}

[1] http://wiki.netbeans.org/DevFaqChangeMenuItemToolbarAppearanceForAction
[2] http://forums.netbeans.org/topic40762.html
[3] http://wiki.netbeans.org/DevFaqAddIconToContextMenu

 

The result:
Shows the result

See sample code at https://github.com/markiewb/nb-api-samples/tree/master/ContextMenuWithIcon