Home » Eclipse Projects » Eclipse 4 » Dynamically create popup menu with parameterized values
| | |
Re: Dynamically create popup menu with parameterized values [message #1830744 is a reply to message #1830562] |
Mon, 03 August 2020 00:04 |
|
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 #1830785 is a reply to message #1830749] |
Mon, 03 August 2020 23:55 |
|
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 #1830815 is a reply to message #1830814] |
Tue, 04 August 2020 17:39 |
Christian Eugster 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 |
|
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:
Then the Command contribution and the declaration of it's two parameters:
Then the command's Handler declaration:
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 #1830845 is a reply to message #1830840] |
Wed, 05 August 2020 07:40 |
Christian Eugster 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?
|
|
| | | |
Goto Forum:
Current Time: Wed Apr 17 22:22:01 GMT 2024
Powered by FUDForum. Page generated in 0.03296 seconds
|