From 5f2682885a16b6f23b4a80b967b56b3e086cbaef Mon Sep 17 00:00:00 2001 From: Reino Ruusu Date: Wed, 6 Mar 2019 11:45:37 +0200 Subject: [PATCH] Presentation of component-specific actions. gitlab #34 Change-Id: I9a88cbaf22c119dbf60a02fc67e7cc98f5d9148b (cherry picked from commit ee7e19e97c21555c72e1e7252eb34104d8137163) --- .../fragment.e4xmi | 1 + .../NetworkElementActionMenuContribution.java | 174 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 org.simantics.district.network.ui/src/org/simantics/district/network/ui/contributions/NetworkElementActionMenuContribution.java diff --git a/org.simantics.district.network.ui/fragment.e4xmi b/org.simantics.district.network.ui/fragment.e4xmi index a77581cd..fb9bde4c 100644 --- a/org.simantics.district.network.ui/fragment.e4xmi +++ b/org.simantics.district.network.ui/fragment.e4xmi @@ -18,6 +18,7 @@ + diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/contributions/NetworkElementActionMenuContribution.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/contributions/NetworkElementActionMenuContribution.java new file mode 100644 index 00000000..b3cc0891 --- /dev/null +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/contributions/NetworkElementActionMenuContribution.java @@ -0,0 +1,174 @@ +package org.simantics.district.network.ui.contributions; + +import java.util.Collections; +import java.util.List; + +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.di.AboutToHide; +import org.eclipse.e4.ui.di.AboutToShow; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.NoSingleResultException; +import org.simantics.db.layer0.SelectionHints; +import org.simantics.db.layer0.util.Layer0Utils; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.district.network.ontology.DistrictNetworkResource; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.scl.compiler.top.ValueNotFound; +import org.simantics.scl.osgi.SCLOsgi; +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function; +import org.simantics.scl.runtime.tuple.Tuple2; +import org.simantics.utils.ui.ISelectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetworkElementActionMenuContribution { + + static private Logger LOGGER = LoggerFactory.getLogger(NetworkElementActionMenuContribution.class); + + @AboutToShow + public void aboutToShow(@Named(IServiceConstants.ACTIVE_SELECTION) Object selection, List items) { + final List vertices = ISelectionUtils.getPossibleKeys(selection, SelectionHints.KEY_MAIN, Resource.class); + if (vertices.size() != 1) + return; + + Resource vertex = vertices.get(0); + + List actions; + try { + actions = Simantics.getSession().syncRequest(new ActionItemRequest(vertex), TransientCacheListener.instance()); + } catch (DatabaseException e) { + LOGGER.error("Error fetching action items for " + vertex, e); + return; + } + + items.add(MMenuFactory.INSTANCE.createMenuSeparator()); + MMenu subMenu = MMenuFactory.INSTANCE.createMenu(); + List children = subMenu.getChildren(); + subMenu.setLabel("Component Actions"); + items.add(subMenu); + + for (Tuple2 action : actions) { + String label = (String) action.c0; + @SuppressWarnings("rawtypes") + Function function = (Function) action.c1; + + Object handler = new Object() { + @CanExecute + public boolean canExecute() { + try { + return Simantics.getSession().syncRequest(new ResourceRead(vertex) { + @Override + public Boolean perform(ReadGraph graph) throws DatabaseException { + DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); + return graph.isInstanceOf(vertex, DN.Element) && graph.hasStatement(vertex, DN.MappedComponent); + } + }, TransientCacheListener.instance()); + } catch (DatabaseException e) { + return false; + } + } + + @Execute + public void execute() { + Simantics.getSession().asyncRequest(new WriteRequest() { + @SuppressWarnings("unchecked") + @Override + public void perform(WriteGraph graph) throws DatabaseException { + DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); + Resource component = graph.getPossibleObject(vertex, DN.MappedComponent); + if (component == null) + return; + + Variable v = Variables.getVariable(graph, graph.getSingleObject(component, ModelingResources.getInstance(graph).ElementToComponent)); + + graph.markUndoPoint(); + Layer0Utils.addCommentMetadata(graph, label + " for " + v.getName(graph)); + + Simantics.applySCLWrite(graph, function, v); + } + }, (DatabaseException e) -> LOGGER.error("Running command " + label + " for " + vertex + " failed", e)); + } + }; + + MDirectMenuItem dynamicItem = MMenuFactory.INSTANCE.createDirectMenuItem(); + dynamicItem.setLabel(label); + dynamicItem.setObject(handler); + children.add(dynamicItem); + } + } + + @AboutToHide + public void aboutToHide() { + } + + private static final class ActionItemRequest extends ResourceRead> { + private ActionItemRequest(Resource resource) { + super(resource); + } + + @SuppressWarnings("unchecked") + @Override + public List perform(ReadGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); + + if (!graph.isInstanceOf(resource, DN.Element)) + return Collections.emptyList(); + + Resource component = graph.getPossibleObject(resource, DN.MappedComponent); + if (component == null) + return Collections.emptyList(); + + Resource mapping = graph.getPossibleObject(resource, DN.HasMapping); + if (mapping == null) + return Collections.emptyList(); + + String name = graph.getPossibleRelatedValue(mapping, DN.Mapping_ComponentType); + if (name == null) + return Collections.emptyList(); + + Resource root = graph.getSingleObject(graph.getSingleObject(mapping, L0.PartOf), L0.PartOf); + Resource uc = Layer0Utils.getPossibleChild(graph, root, name); + if (uc == null) + return Collections.emptyList(); + + Resource actionsModule = Layer0Utils.getPossibleChild(graph, uc, "Actions"); + if (actionsModule == null) + return Collections.emptyList(); + + String uri = graph.getURI(actionsModule); + SCLContext sclContext = SCLContext.getCurrent(); + Object oldGraph = sclContext.put("graph", graph); + try { + @SuppressWarnings("rawtypes") + Function actionsFun = (Function) SCLOsgi.MODULE_REPOSITORY.getValue(uri, "actions"); + Variable variable = Variables.getPossibleVariable(graph, graph.getSingleObject(component, ModelingResources.getInstance(graph).ElementToComponent)); + return (List) actionsFun.apply(variable); + } + catch (ValueNotFound e) { + throw new NoSingleResultException("No value for " + uri + "/actions", e); + } + finally { + sclContext.put("graph", oldGraph); + } + } + } +} -- 2.45.2