Issue
I am developing a NetBeans plugin which requires the use of "dynamic" menus because currently one has to hard code in a class which is dedicated to a certain menu item and its action. However I wish to allow the user through the UI provided by the plugin to be able to change the values for the menu items (what they do - this would be dealt with with variables in the main method, I would not allow the user to write the code for the main method themselves -, what they are called and their associated keyboard shortcuts) as well as to add and remove menu items. My plugin would probably read these preferences from a file and would ideally have just one class which would create all these dynamic menu items with their values defined within the preferences file.
I understand that there is a way of doing this, but the only real information I could find on it was this thread and the bugzilla page it links to seems to be down at the moment so that doesn't really help me... So how exactly can one make a dynamic menu with dynamic menu items?
I have NetBeans version 8.1 and JDK8. Also, when I say "dynamic menu item" or similar I am talking about the actual options provided to you from the menu that do that stuff (whatever stuff the plugin is there to do, in my case it copies certain data to the clipboard when one of these options is clicked).
Solution
I use dynamic menu in my netbeans RCP application. Below is the general format I use for adding dynamic menu items to right-click menus, toolbars, menu-bar...
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.awt.Actions;
import org.openide.awt.DynamicMenuContent;
import org.openide.util.actions.Presenter;
/* Register your dynamic action using annotations (perferred over layer.xml entries)
@ActionID(id = "ExampleDynamicMenu", category = "Edit")
@ActionRegistration(lazy = false, displayName = "ExampleDynamicMenu")
@ActionReferences({
@ActionReference(path = "Loaders/folder/any/Actions", position = 666),
@ActionReference(path = "Loaders/content/unknown/Actions", position = 666),
@ActionReference(path = "Loaders/text/xml/Actions", position = 666),
@ActionReference(path = "Projects/Actions", position = 666),
@ActionReference(path = "Editors/TabActions", position = 666)
})
*/
public class ExampleDynamicMenu extends AbstractAction implements DynamicMenuContent, Presenter.Popup {
@Override
public JMenuItem getPopupPresenter() {
JMenu menu = new JMenu(this);
JComponent[] menuItems = createMenu();
for (JComponent item : menuItems) {
menu.add(item);
}
return menu;
}
@Override
public void actionPerformed(ActionEvent e) {
// does nothing, this is a popup menu
}
@Override
public JComponent[] getMenuPresenters() {
return createMenu();
}
@Override
public JComponent[] synchMenuPresenters(JComponent[] items) {
return createMenu();
}
private JComponent[] createMenu() {
List<JComponent> items = new ArrayList<>(20);
//TODO: Load the list of actions stored in the preferences, and for each action add a menu-item to the dynamic menu.
// Note: You preferences can simply store the Action's category and id; then you can always get the action instances using
// Action action = Actions.forID(category_string, id_string);
List<Action> actionsList = YOUR_PREFERENCES_GETTER.getActions(); //You have to figure out how to store and retrieve user's preferred actions list yourself :)
for (Action action : actionsList) {
if (action == null) { //Assume null means add a separator
if (items.size() > 0 && !(items.get(items.size() - 1) instanceof JSeparator)) { //Only add separators after actions.
items.add(new JPopupMenu.Separator());
}
} else { //Convert action to menu item, and build your dynamic menu
items.add(toMenuItem(action));
}
}
return items.toArray(new JComponent[items.size()]);
}
/**
* Creates a menu item from an action.
*
* @param action an action
* @return JMenuItem
*/
private static JMenuItem toMenuItem(Action action) {
JMenuItem item;
if (action instanceof Presenter.Menu) {
item = ((Presenter.Menu) action).getMenuPresenter();
} else if (action instanceof Presenter.Popup) {
item = ((Presenter.Popup) action).getPopupPresenter();
} else {
item = new JMenuItem();
Actions.connect(item, action, false);
}
return item;
}
}
Answered By - sproger