package org.simantics.district.network.ui.styles; import java.awt.geom.Point2D; import java.util.Collections; import java.util.List; import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.exception.MissingVariableException; import org.simantics.db.layer0.exception.MissingVariableValueException; import org.simantics.db.layer0.exception.PendingVariableException; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.diagram.profile.StyleBase; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.district.network.DistrictNetworkUtil; import org.simantics.district.network.ontology.DistrictNetworkResource; import org.simantics.district.network.ui.nodes.DistrictNetworkHoverInfoNode; import org.simantics.district.network.ui.nodes.DistrictNetworkNodeUtils; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.scenegraph.INode; import org.simantics.scenegraph.profile.EvaluationContext; import org.simantics.scenegraph.profile.common.ProfileVariables; 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.Function1; import org.simantics.scl.runtime.tuple.Tuple3; import org.simantics.structural.stubs.StructuralResource2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DistrictNetworkHoverInfoStyle extends StyleBase { private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkHoverInfoStyle.class); private static final String ACTIONS_MODULE = "Actions"; private static final String HOVER_CONTRIBUTION = "hoverContribution"; public class StyleResult { Point2D origin; List labels; public StyleResult(Point2D origin, List labels) { this.origin = origin; this.labels = labels; } public Point2D getOrigin() { return origin; } public List getLabels() { return labels; } } public DistrictNetworkHoverInfoStyle(Resource style) throws DatabaseException { super(style); } String currentRowKey; protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException { ModelingResources MOD = ModelingResources.getInstance(graph); DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent); return mappedElement != null ? graph.getPossibleObject(mappedElement, MOD.ElementToComponent) : null; } @Override public StyleResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource mapElement, Variable configuration) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); String variableURI = graph.getPossibleRelatedValue(runtimeDiagram, DIA.RuntimeDiagram_HasVariable, Bindings.STRING); Variable activeVariable = org.simantics.db.layer0.variable.Variables.getPossibleVariable(graph, variableURI); if (activeVariable == null) return null; Resource module = DistrictNetworkUtil.getMappedComponentCached(graph, mapElement); if (module == null) return null; Resource moduleType = graph.getPossibleType(module, STR.Component); if (moduleType == null) return null; Function1> function = getUCTextGridFunctionCached(graph, moduleType); if (function == null) return null; List result; try { Variable variable = Variables.getVariable(graph, module); Variable moduleVariable = Variables.possibleActiveVariable(graph, variable); if (moduleVariable == null) moduleVariable = variable; result = Simantics.applySCLRead(graph, function, moduleVariable); } catch (PendingVariableException | MissingVariableValueException e) { result = Collections.singletonList(new Tuple3("", "", "")); } catch (MissingVariableException e) { // the requested variable is missing from the UC String message = e.getMessage(); LOGGER.warn("Missing variable for calculating style with function {} {}", function, message); result = Collections.singletonList(new Tuple3("<" + message +">", "", "")); } Point2D point; DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); if (graph.isInstanceOf(mapElement, DN.Vertex)) { double[] coords = graph.getRelatedValue(mapElement, DIA.HasLocation); point = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double(coords[0], coords[1]), null); } else if (graph.isInstanceOf(mapElement, DN.Edge)) { Resource v1 = graph.getSingleObject(mapElement, DN.HasStartVertex); double[] coords1 = graph.getRelatedValue(v1, DIA.HasLocation); Resource v2 = graph.getSingleObject(mapElement, DN.HasEndVertex); double[] coords2 = graph.getRelatedValue(v2, DIA.HasLocation); point = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double((coords1[0] + coords2[0]) / 2, (coords1[1] + coords2[1]) / 2), null); } else { return null; } return new StyleResult(point, result); } @Override public void applyStyleForNode(EvaluationContext observer, INode parent, StyleResult results) { if (results == null) { cleanupStyleForNode(observer, parent); return; } DistrictNetworkHoverInfoNode node = ProfileVariables.claimChild(parent, "*", DistrictNetworkHoverInfoNode.NODE_KEY, DistrictNetworkHoverInfoNode.class, observer); if (node == null) return; node.setLabels(results.getLabels()); node.setOrigin(results.getOrigin()); } @Override protected void cleanupStyleForNode(EvaluationContext observer, INode node) { ProfileVariables.denyChild(node, "*", DistrictNetworkHoverInfoNode.NODE_KEY); } private static Function1> getUCTextGridFunctionCached(ReadGraph graph, Resource componentType) throws DatabaseException { return graph.syncRequest(new UCTextGridFunctionRequest(componentType), TransientCacheListener.instance()); } private static final class UCTextGridFunctionRequest extends ResourceRead>> { public UCTextGridFunctionRequest(Resource resource) { super(resource); } @SuppressWarnings("unchecked") @Override public Function1> perform(ReadGraph graph) throws DatabaseException { Resource actionsModule = Layer0Utils.getPossibleChild(graph, resource, ACTIONS_MODULE); if (actionsModule == null || !graph.isInstanceOf(actionsModule, Layer0.getInstance(graph).SCLModule)) return null; String uri = graph.getURI(actionsModule); SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.get("graph"); try { sclContext.put("graph", graph); return (Function1>) SCLOsgi.MODULE_REPOSITORY.getValue(uri, HOVER_CONTRIBUTION); } catch (ValueNotFound e1) { return null; } finally { sclContext.put("graph", oldGraph); } } } }