/******************************************************************************* * Copyright (c) 2017 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Semantum Oy - initial API and implementation *******************************************************************************/ package org.simantics.modeling.adapters; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; 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.scenegraph.INode; import org.simantics.scenegraph.g2d.G2DNodeModification; import org.simantics.scenegraph.g2d.IG2DNode; import org.simantics.scenegraph.g2d.nodes.ConnectionNode; import org.simantics.scenegraph.g2d.nodes.SVGNode; import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment; import org.simantics.scenegraph.g2d.nodes.SingleElementNode; import org.simantics.scenegraph.g2d.nodes.TargetedSVGNodeAssignment; import org.simantics.scenegraph.g2d.nodes.TransformationAssignment; import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode; import org.simantics.scenegraph.profile.EvaluationContext; import org.simantics.scenegraph.utils.NodeUtil; import org.simantics.scl.runtime.function.Function; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.utils.datastructures.Pair; /** * @author Antti Villberg * @since 1.29.0 */ public class SymbolCodeStyle extends StyleBase> { @Override public Pair calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); // Find a component for the element Variable elementVariable = Variables.getPossibleVariable(graph, element); if (elementVariable == null) return null; Object modi = elementVariable.getPossiblePropertyValue(graph, DIA.symbolCode); if (modi == null) { if(graph.isInstanceOf(element, DIA.RouteGraphConnection)) { StructuralResource2 STR = StructuralResource2.getInstance(graph); Resource connectionType = graph.getPossibleObject(element, STR.HasConnectionType); if(connectionType != null) { Variable connectionTypeVariable = Variables.getPossibleVariable(graph, connectionType); Function fn = connectionTypeVariable.getPossiblePropertyValue(graph, DIA.symbolFunction); modi = Simantics.applySCLRead(graph, fn, elementVariable); } } } if(modi == null) return null; // If element is moved, recalculate style Object transform = graph.getPossibleRelatedValue(element, DIA.HasTransform); if (modi instanceof G2DNodeModification) { return Pair.make((G2DNodeModification)modi, transform); } else if (modi instanceof List) { @SuppressWarnings("unchecked") List styles = (List)modi; List assignments = new ArrayList<>(styles.size()/3); for (int i = 0; i < styles.size()/3; i++) assignments.add(new SVGNodeAssignment(styles.get(3*i), styles.get(3*i+1), styles.get(3*i+2))); return Pair.make(new G2DNodeModification(assignments, Collections.emptyList()), transform); } else { throw new DatabaseException("Invalid symbolCode value: " + modi); } } private Map buildSingleElementMap(INode node) { Map elements = new HashMap<>(); NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> { elements.put(n.getKey(), n); return null; }); return elements; } @Override public void applyStyleForNode(EvaluationContext evaluationContext, INode node, Pair result) { if (result == null || result.first == null) return; Map elements = null; G2DNodeModification modification = result.first; if(node instanceof ConnectionNode) { if (modification.svgAssignments != null && !modification.svgAssignments.isEmpty()) { INode child = NodeUtil.getFirstChild(node); if(child instanceof RouteGraphNode) { RouteGraphNode rgn = (RouteGraphNode)child; rgn.setAssignments(modification.svgAssignments); } } } else if(node instanceof SingleElementNode) { Map> assignmentMap = new HashMap<>(); if (modification.svgAssignments != null && !modification.svgAssignments.isEmpty()) { for (SVGNode p : NodeUtil.collectNodes(node, SVGNode.class)) { List list = assignmentMap.get(p); if(list == null) { list = new ArrayList<>(); assignmentMap.put(p, list); } list.addAll(modification.svgAssignments); } } if(modification.targetedSVGAssignments != null && !modification.targetedSVGAssignments.isEmpty()) { elements = buildSingleElementMap(node); for(TargetedSVGNodeAssignment ass : modification.targetedSVGAssignments) { SingleElementNode sen = elements.get(ass.singleElementKey); for (SVGNode p : NodeUtil.collectNodes(sen, SVGNode.class)) { List list = assignmentMap.get(p); if(list == null) { list = new ArrayList<>(); assignmentMap.put(p, list); } list.add(ass); } } } for(Map.Entry> entry : assignmentMap.entrySet()) { SVGNode p = entry.getKey(); p.setAssignments(entry.getValue()); p.cleanDiagramCache(); } if (modification.transformAssignments != null) { Map trs = new HashMap<>(); for (TransformationAssignment ass : modification.transformAssignments) trs.put(ass.key, ass.transform); NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> { Object key = n.getKey(); AffineTransform tr = trs.get(key); if (tr != null) { IG2DNode[] children = n.getSortedNodes(); if (children.length > 0) children[0].setTransform(tr); } return null; }); } } } }