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.eclipse.swt.widgets.Display; 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.modeling.ui.scl.SCLScripts; 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.reporting.SCLReportingHandler; 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, Display display, 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; } if (actions == null || actions.isEmpty()) 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() { // Handler that only opens the SCL script console on demand SCLReportingHandler handler = new SCLReportingHandler() { private SCLReportingHandler handler; // Get a handler for the SCL script console view private SCLReportingHandler getHandler() { if (handler == null) { handler = SCLScripts.getOrCreateConsoleCommandSession().second; } return handler; } @Override public void printError(String error) { display.asyncExec(() -> { getHandler().printError(error); }); } @Override public void printCommand(String command) { display.asyncExec(() -> { getHandler().printCommand(command); }); } @Override public void print(String text) { display.asyncExec(() -> { getHandler().print(text); }); } @Override public void didWork(double amount) { display.asyncExec(() -> { getHandler().didWork(amount); }); } }; 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)); SCLContext context = SCLContext.getCurrent(); Object oldHandler = context.put(SCLReportingHandler.REPORTING_HANDLER, handler); try { Simantics.applySCLWrite(graph, function, v); } finally { context.put(SCLReportingHandler.REPORTING_HANDLER, oldHandler); } } }, (DatabaseException e) -> { if (e != null) 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); } } } }