Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Dynamically create popup menu with parameterized values
Dynamically create popup menu with parameterized values [message #1830562] Wed, 29 July 2020 08:49 Go to next message
Christian Eugster is currently offline Christian EugsterFriend
Messages: 203
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi
I try to add popup menu items in a tree view by using Dynamic menu contribution in an *.e4.xmi file. My related class has a @AboutToShow method where I build some direct menu items. The selected tree object contains a list property and I want to show for each of these properties a menu item. How can I provide the menu items with an individual entry of the tree objects list, so that each menu item acts depending of the provided list entry? In AboutToShow there I see no opportunity to do that. Any hints?
Christian
Re: Dynamically create popup menu with parameterized values [message #1830655 is a reply to message #1830562] Thu, 30 July 2020 15:04 Go to previous messageGo to next message
Christian Eugster is currently offline Christian EugsterFriend
Messages: 203
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi
I try to precise my first message: In the tree view, there is a selected element, that has a unknown number of children of same type. I need for each child a menu entry. With @AboutToShow I am able to create a menu item for each child. But because the Handler is lazy instantiated, when I click a menu entry, and not before, I cannot the handler, which child it is representing. I would like to set an attribute in the handlers, so that they "know" which child they are representing.
Thanks Christian
Re: Dynamically create popup menu with parameterized values [message #1830667 is a reply to message #1830655] Thu, 30 July 2020 20:10 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
I am not sure what you mean, your description is still not very clear.

But on each model element there are ways to store extra data in the element, have a look at 'getTags()', 'getPersistedState()' and 'getTransientData()'.

Also have a look at the parameters that you can provide to a HandledMenuItem, they will be provided to a Handler, if the command defines the parameters too.


Re: Dynamically create popup menu with parameterized values [message #1830744 is a reply to message #1830562] Mon, 03 August 2020 00:04 Go to previous messageGo to next message
Craig Foote is currently offline Craig FooteFriend
Messages: 217
Registered: July 2009
Senior Member
I'm trying to do something similar - create a 'Show View' dynamic menu. In @AboutToShow method:


package ca.footeware.tasks.ui.handlers;

import java.util.List;

import org.eclipse.e4.ui.di.AboutToShow;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.commands.MCommand;
import org.eclipse.e4.ui.model.application.commands.MParameter;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
import org.eclipse.e4.ui.workbench.modeling.EModelService;

public class ShowViewDynamicMenu {

	@AboutToShow
	public void aboutToShow(List<MMenuElement> items, EModelService modelService, MApplication application) {
		List<MCommand> mCommands = modelService.findElements(application,
				"ca.footeware.e4.application.ui.command.showview", MCommand.class);
		MCommand showViewCommand = mCommands.get(0);

		List<MPart> mParts = modelService.findElements(application, null, MPart.class);
		for (MPart mPart : mParts) {
			String label = mPart.getLabel();
			String elementId = mPart.getElementId();

			MHandledMenuItem dynamicItem = modelService.createModelElement(MHandledMenuItem.class);
			dynamicItem.setLabel(label);

			MParameter mParameter = modelService.createModelElement(MParameter.class);
			mParameter.setName("partid");
			mParameter.setValue(elementId);
			dynamicItem.getParameters().add(mParameter);
			dynamicItem.setCommand(showViewCommand);

			items.add(dynamicItem);
		}
	}

}


But when I run and reveal on one of the generated menuitems I get this message (nothing happens when I click one):

!ENTRY org.eclipse.e4.ui.workbench 4 0 2020-08-02 20:01:28.267
!MESSAGE Unable to generate the parameterized command with the id "ca.footeware.e4.application.ui.command.showview" with the {partid=ca.footeware.tasks.ui.part.details} parameter(s). Model details: ca.footeware.e4.application.ui.dynamicmenucontribution.showpart.2=org.eclipse.e4.ui.model.application.ui.menu.impl.HandledMenuItemImpl@2d272b0d (tags: null, contributorURI: null) (widget: null, renderer: org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer@2b5183ec, toBeRendered: true, onTop: false, visible: true, containerData: null, accessibilityPhrase: null) (label: Details, iconURI: null, tooltip: null, enabled: true, selected: false, type: Push) (mnemonics: null) (wbCommand: null)


Can someone tell me what I've done wrong please?

Craig
Re: Dynamically create popup menu with parameterized values [message #1830749 is a reply to message #1830744] Mon, 03 August 2020 05:45 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
Make sure that the parameter is also defined on the MCommand, you can only pass arguments/parameters to a command when it has parameters defined.
Re: Dynamically create popup menu with parameterized values [message #1830785 is a reply to message #1830749] Mon, 03 August 2020 23:55 Go to previous messageGo to next message
Craig Foote is currently offline Craig FooteFriend
Messages: 217
Registered: July 2009
Senior Member
Thanks Rolf. It was indeed my use of parameters, specifically:

mParameter.setName("partid");


should have used the parameter's element ID.


Now I have another problem. I'm programmatically opening a view which injects a MDirtyable as a field but it's throwing an exception:

!ENTRY org.eclipse.e4.ui.workbench 4 0 2020-08-03 19:53:14.212
!MESSAGE Unable to create class 'ca.footeware.tasks.ui.parts.DetailsPart' from bundle '6'
!STACK 0
org.eclipse.e4.core.di.InjectionException: Unable to process "DetailsPart.dirty": no actual value was found for the argument "MDirtyable".

Any ideas? It appears the MDirtyable cannot be injected yet it works if the view is opened on startup.
Re: Dynamically create popup menu with parameterized values [message #1830814 is a reply to message #1830562] Tue, 04 August 2020 17:05 Go to previous messageGo to next message
Christian Eugster is currently offline Christian EugsterFriend
Messages: 203
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
I think, with parameter it should work. But I do not know, how I get the parameter in my menu class.
Re: Dynamically create popup menu with parameterized values [message #1830815 is a reply to message #1830814] Tue, 04 August 2020 17:39 Go to previous messageGo to next message
Christian Eugster is currently offline Christian EugsterFriend
Messages: 203
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
I try to precise my problem: In the tree view, I have an entry that contains further elements, that are not shown (e.g. entry "level" has a collection of sub entries like e.g. "first level", "second level", and "third level". When I click the entry "level", I want for each sub level a menu item, so that the user can select, which sub element he wants to use. These sub elements and their number change for each "level" object. With @AboutToShow I succeeded to add a direct menu item, e.g. "first level", "second level" e.t.c. But I am not able to parameterize the handlers with the information, which sub element it stands for, because instantiation of the handlers is not before I select the menu item. So I don't know, how to achieve to provide my handler classes with the information, which sub element of the tree item it represents.
Re: Dynamically create popup menu with parameterized values [message #1830825 is a reply to message #1830815] Tue, 04 August 2020 21:46 Go to previous messageGo to next message
Craig Foote is currently offline Craig FooteFriend
Messages: 217
Registered: July 2009
Senior Member
Hi Christian, I'm not sure I'm doing it the best way but I've got parameters working. I'll try to detail what I did. I'll start with the model additions in the Application.e4xmi:

First the dynamic menu contribution and the class with the method annotated with @AboutToShow:
index.php/fa/38726/0/

Then the Command contribution and the declaration of it's two parameters:
index.php/fa/38727/0/

Then the command's Handler declaration:
index.php/fa/38728/0/

Then the rest is code. In my ShowViewDynamicMenu.java:
public class ShowViewDynamicMenu {

	@AboutToShow
	public void aboutToShow(List<MMenuElement> items, EModelService modelService, MApplication application) {
		List<MCommand> mCommands = modelService.findElements(application, "ca.footeware.e4.application.ui.command.showview", MCommand.class);
		MCommand showViewCommand = mCommands.get(0);

		List<MPart> mParts = modelService.findElements(application, null, MPart.class);
		Set<MPart> uniqueParts = new HashSet<>();
		Set<String> labels = new HashSet<>();
		for (MPart mPart : mParts) {
			String label = mPart.getLabel();
			if (!labels.contains(label)) {
				labels.add(label);
				uniqueParts.add(mPart);
			}
		}

		for (MPart mPart : uniqueParts) {
			String label = mPart.getLabel();
			String elementId = mPart.getElementId();
			String contributionURI = mPart.getContributionURI();

			MHandledMenuItem dynamicItem = modelService.createModelElement(MHandledMenuItem.class);
			dynamicItem.setLabel(label);

			MParameter mParameter = modelService.createModelElement(MParameter.class);
			mParameter.setName("ca.footeware.e4.application.ui.commandparameter.partid");
			mParameter.setValue(elementId);
			dynamicItem.getParameters().add(mParameter);

			mParameter = modelService.createModelElement(MParameter.class);
			mParameter.setName("ca.footeware.e4.application.ui.commandparameter.contributionURI");
			mParameter.setValue(contributionURI);
			dynamicItem.getParameters().add(mParameter);

			dynamicItem.setCommand(showViewCommand);

			items.add(dynamicItem);
		}
	}


As you can see, I'm "find"ing the command by id for later insertion into the dynamicItem (menuitem). In my case I'm then getting all the parts declared in the model so that I can build my Show View menu. Your logic would be different. But then I create the dynamicItem and insert into it the two parameters and their values. What is important here is the mParameter.setName() gets passed the command parameter's ID not name.

In the Handler class:
public class ShowViewHandler {

	@Execute
	public void execute(@Named("ca.footeware.e4.application.ui.commandparameter.partid") String partId,
			@Named("ca.footeware.e4.application.ui.commandparameter.contributionURI") String contributionURI,
			EPartService partService, MMenuItem menuItem, IEclipseContext ctx, EModelService modelService,
			MApplication application) {

		IEclipseContext newPartContext = ctx.createChild(partId + "_context");
		MPart newPart = MBasicFactory.INSTANCE.createPart();
		newPart.setContext(newPartContext);
		newPart.setContributionURI(contributionURI);
		newPart.setCloseable(true);
		newPart.setLabel(menuItem.getLabel());
		List<MPartStack> partStackList = modelService.findElements(application, null, MPartStack.class, null);
		MPartStack mPartStack = partStackList.get(0);
		mPartStack.setVisible(true);
		mPartStack.getChildren().add(newPart);
		partService.activate(newPart, true);
	}


I'm injecting into the @execute method the two parameters and some services. Some magic there. The rest of the code is domain specific and would be different than your handler, but you should be able to use the parameters.

Hope that helps,
Craig

Now if I could just get one of my Parts to open up and get injected with an MDirtyable I'd be done... but it's coming in null. Probably needs to be added to the context I create in the above handler...
Re: Dynamically create popup menu with parameterized values [message #1830840 is a reply to message #1830825] Wed, 05 August 2020 06:16 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
Hi Craig,

Thanks for the answer, I would have done it similarly (never used dynamic menu items before).

With respect to the MDirtyable, does the code work when you insert a MPart instead? If it does, please open a bug on Platform-UI, MPart extends MDirtyable so the code should work with that as well.
Otherwise, the MDirtyable/MPart might not be in the context yet (which seems very strange too, i.e. could be a bug too), in that case use @Optional
Re: Dynamically create popup menu with parameterized values [message #1830845 is a reply to message #1830840] Wed, 05 August 2020 07:40 Go to previous messageGo to next message
Christian Eugster is currently offline Christian EugsterFriend
Messages: 203
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi Craig
thank you for the good description. I adapted your examples for my project. It seems that I am a step further, but executing, I get the error

!MESSAGE Command 'ch.eugster.herakles.description.command.description.add' failed
!STACK 0
org.eclipse.core.commands.ExecutionException: ch.eugster.herakles.description.handlers.AddHandler handler is missing @Execute
	at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:160)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:488)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:487)
	at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:213)
	at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.executeItem(HandledContributionItem.java:438)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.handleWidgetSelection(AbstractContributionItem.java:449)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.lambda$2(AbstractContributionItem.java:475)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem$$Lambda$261/0000000000000000.handleEvent(Unknown Source)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4385)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1512)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1535)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1520)
	at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:1324)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4172)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3789)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.dropdownEvent(AbstractContributionItem.java:425)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.handleWidgetSelection(AbstractContributionItem.java:436)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.lambda$2(AbstractContributionItem.java:475)
	at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem$$Lambda$261/0000000000000000.handleEvent(Unknown Source)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4385)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1512)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1535)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1520)
	at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:1324)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4172)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3789)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1158)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1047)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
	at org.eclipse.e4.ui.internal.workbench.swt.E4Application.start(E4Application.java:166)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:137)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:107)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:401)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:657)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:594)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1447)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1420)
Caused by: org.eclipse.core.commands.NotHandledException: org.eclipse.ui.internal.WorkbenchHandlerServiceHandler
	at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:161)
	... 45 more


My Handler looks like this:

package ch.eugster.herakles.description.handlers;

import javax.annotation.PostConstruct;
import javax.inject.Named;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.osgi.service.event.Event;

import ch.eugster.herakles.description.Activator;
import ch.eugster.herakles.description.DescriptionUnitConstants;
import ch.eugster.herakles.description.dialogs.TectonicsDialog;
import ch.eugster.herakles.description.views.DescriptionUnitTreeView;
import ch.eugster.herakles.persistence.api.model.DescriptionUnit;
import ch.eugster.herakles.persistence.api.query.DescriptionUnitQuery;
import ch.eugster.herakles.ui.handlers.AbstractEntityHandler;

public class AddHandler extends AbstractEntityHandler implements IMenuListener
{
	public AddHandler()
	{
		System.out.println();
	}

	@PostConstruct()
	private void postConstruct()
	{
	}

	@Execute
	public void execute(Shell shell, @Named(DescriptionUnitConstants.DESCRIPTION_UNIT_COMMAND_PARAMETER_1_ADD) String tectonicsLevelId, @Named(DescriptionUnitConstants.DESCRIPTION_UNIT_COMMAND_PARAMETER_2_ADD) String contributionURI, MenuItem menuItem, IEclipseContext context)
	{
		if (this.partService.getActivePart().getObject() instanceof DescriptionUnitTreeView)
		{
			DescriptionUnit entity = null;
			MPart part = this.partService.findPart(DescriptionUnitConstants.TECTONICS_TREE_VIEW_ID);
			DescriptionUnitTreeView view = (DescriptionUnitTreeView) part.getObject();
			IStructuredSelection ssel = (IStructuredSelection) view.getViewer().getSelection();
			DescriptionUnitQuery query = this.persistenceService.getQuery(DescriptionUnitQuery.class);
			if (ssel.isEmpty())
			{
				TectonicsDialog dialog = new TectonicsDialog(shell, this.persistenceService);
				if (dialog.open() == IDialogConstants.OK_ID)
				{
					entity = query.newInstance(dialog.getSelectedTectonicsLevel());
				}
			}
			else
			{
				DescriptionUnit parent = (DescriptionUnit) ssel.getFirstElement();
				entity = query.newInstance(parent, null);
				Activator.getInstance().showEditor(this.modelService, this.partService, this.application, entity, PartState.ACTIVATE);
			}
		}
	}

	@Override
	@CanExecute
	public boolean canExecute()
	{
		return super.canExecute();
	}

	@Override
	public void handleEvent(Event event)
	{
	}

	@Override
	protected void subscribeEvents()
	{
	}

	@Override
	public void menuAboutToShow(IMenuManager manager)
	{
		System.out.println();
	}
}


As you can see there is an @Execute annotation. Why does the program not "see" it?
Re: Dynamically create popup menu with parameterized values [message #1830848 is a reply to message #1830845] Wed, 05 August 2020 08:20 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
All the parameters of the @Execute will be taken from the context. The method will not be able to execute when some of the parameters are not available in the context. Therefore, no @Execute method with all available parameters can be found, and it will not execute.
Try removing the unused parameters, menuItem and context.
Re: Dynamically create popup menu with parameterized values [message #1830849 is a reply to message #1830848] Wed, 05 August 2020 08:23 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
Moreover, shell is also not used. Also you can get the MPart injected, it is in the context too. You might need a named attribute too to get the active part from the context.
Re: Dynamically create popup menu with parameterized values [message #1830850 is a reply to message #1830849] Wed, 05 August 2020 08:38 Go to previous message
Christian Eugster is currently offline Christian EugsterFriend
Messages: 203
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi Rolf
removing the menu item and context parameters did it! I do yet not know why but I will try to find out. Thank you!
Previous Topic:Toolbar not resize after IElementUpdater
Next Topic:Composite Part Orientation
Goto Forum:
  


Current Time: Tue Apr 23 13:19:52 GMT 2024

Powered by FUDForum. Page generated in 0.05371 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top