package org.simantics.district.network.ui.styles; import java.awt.geom.Point2D; import java.util.Objects; import java.util.Set; import org.simantics.Simantics; 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.profile.MidBranchEdgeSetRequest; import org.simantics.district.network.ui.nodes.DeferredRenderingNode; import org.simantics.district.network.ui.nodes.DistrictNetworkEdgeNode; import org.simantics.district.network.ui.nodes.DistrictNetworkNodeUtils; import org.simantics.district.network.ui.nodes.DistrictNetworkStaticInfoNode; import org.simantics.layer0.Layer0; import org.simantics.scenegraph.INode; import org.simantics.scenegraph.ParentNode; import org.simantics.scenegraph.g2d.IG2DNode; import org.simantics.scenegraph.g2d.nodes.ConnectionNode; import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode; import org.simantics.scenegraph.profile.EvaluationContext; import org.simantics.scenegraph.profile.common.ProfileVariables; import org.simantics.scenegraph.utils.NodeUtil; 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.structural.stubs.StructuralResource2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Deprecated public class DistrictNetworkStaticInfoStyle extends StyleBase { private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkStaticInfoStyle.class); private static final String ACTIONS_MODULE = "Actions"; private static final String PIPELINE_INFO = "pipelineInfo"; public static final String STATIC_INFO_DEFERRED = "staticInfo"; public static class StyleResult { public StyleResult(Resource r, Point2D p1, String info) { this.r = r; this.p1 = p1; this.info = info; } public final Resource r; public final Point2D p1; public final String info; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + r.hashCode(); result = prime * result + ((info == null) ? 0 : info.hashCode()); result = prime * result + ((p1 == null) ? 0 : p1.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; StyleResult other = (StyleResult) obj; return r.equals(other.r) && Objects.equals(info, other.info) && Objects.equals(p1, other.p1); } } public DistrictNetworkStaticInfoStyle(Resource style) { super(style); } private static final Point2D EDGE = new Point2D.Double(); @Override public StyleResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource mapElement) throws DatabaseException { return calculateStyle(graph, entry, mapElement); } public static StyleResult calculateStyle(ReadGraph graph, Resource entry, Resource mapElement) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Set types = graph.getTypes(mapElement); boolean isEdge = types.contains(DN.Edge); boolean isVertex = types.contains(DN.Vertex); if (!isEdge && !isVertex) return null; if (isEdge) { Resource diagram = graph.getSingleObject(mapElement, Layer0.getInstance(graph).PartOf); Set edgesToUse = graph.syncRequest(new MidBranchEdgeSetRequest(diagram), TransientCacheListener.instance()); if (!edgesToUse.contains(mapElement)) return null; } Resource module = DistrictNetworkUtil.getMappedComponentCached(graph, mapElement); if (module == null) return null; StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource moduleType = graph.getPossibleType(module, STR.Component); if (moduleType == null) return null; Function1 function = getUCPipelineInfoFunctionCached(graph, moduleType); if (function == null) return null; String 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 = null; } 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 = "<" + message + ">"; } if (isVertex) { DiagramResource DIA = DiagramResource.getInstance(graph); double[] coords = graph.getRelatedValue(mapElement, DIA.HasLocation); Point2D p = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double(coords[0], coords[1]), null); return new StyleResult(mapElement, p, result); } else if (isEdge) { return new StyleResult(mapElement, EDGE, result); } return null; } @Override public void applyStyleForNode(EvaluationContext evaluationContext, INode parent, StyleResult result) { if (result == null) { cleanupStyleForNode(evaluationContext, parent); return; } ParentNode root = (ParentNode) NodeUtil.getNearestParentOfType(parent, RTreeNode.class); if (root != null) { DeferredRenderingNode deferred = ProfileVariables.claimChild(root, "", STATIC_INFO_DEFERRED, DeferredRenderingNode.class, evaluationContext); deferred.setZIndex(Integer.MAX_VALUE-1); } DistrictNetworkStaticInfoNode node = ProfileVariables.claimChild(parent, "*", DistrictNetworkStaticInfoNode.NODE_KEY, DistrictNetworkStaticInfoNode.class, evaluationContext); if (node == null) return; Point2D p1 = result.p1; if (p1 != EDGE) { node.setLocation(p1, new Point2D.Double(1.0, 0.0)); } else { // StaticInfoNode takes care of positioning the text during render // based on the found DistrictNetworkEdgeNode's information. for (IG2DNode n : ((ConnectionNode)parent).getNodes()) { if (n instanceof DistrictNetworkEdgeNode) { node.setEdgeNode((DistrictNetworkEdgeNode) n); } } } node.setInfo(result.info); } private static Function1 getUCPipelineInfoFunctionCached(ReadGraph graph, Resource componentType) throws DatabaseException { return graph.syncRequest(new UCPipelineInfoRequest(componentType), TransientCacheListener.instance()); } private static final class UCPipelineInfoRequest extends ResourceRead> { public UCPipelineInfoRequest(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, PIPELINE_INFO); } catch (ValueNotFound e1) { return null; } finally { sclContext.put("graph", oldGraph); } } } @Override protected void cleanupStyleForNode(EvaluationContext evaluationContext, INode node) { ProfileVariables.denyChild(node, "*", DistrictNetworkStaticInfoNode.NODE_KEY); } }