X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2Fdiagram%2Fstyle%2FTypicalInheritanceStyle.java;fp=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2Fdiagram%2Fstyle%2FTypicalInheritanceStyle.java;h=c0de412678315b21ceb99ba0832e6bf281295131;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/TypicalInheritanceStyle.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/TypicalInheritanceStyle.java new file mode 100644 index 000000000..c0de41267 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/TypicalInheritanceStyle.java @@ -0,0 +1,250 @@ +package org.simantics.modeling.ui.diagram.style; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; +import java.awt.geom.Rectangle2D; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.PossibleTypedParent; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.diagram.connection.RouteGraph; +import org.simantics.diagram.connection.RouteGraphConnectionClass; +import org.simantics.diagram.connection.RouteTerminal; +import org.simantics.diagram.content.ConnectionUtil; +import org.simantics.diagram.handler.Paster; +import org.simantics.diagram.handler.Paster.RouteLine; +import org.simantics.diagram.profile.ProfileKeys; +import org.simantics.diagram.profile.StyleBase; +import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.diagram.handler.DataElementMap; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.SelectionOutline; +import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline; +import org.simantics.modeling.ModelingResources; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.ParentNode; +import org.simantics.scenegraph.g2d.IdentityAffineTransform; +import org.simantics.scenegraph.g2d.nodes.ConnectionNode; +import org.simantics.scenegraph.g2d.nodes.DecorationShapeNode; +import org.simantics.scenegraph.g2d.nodes.ShapeNode; +import org.simantics.scenegraph.profile.DataNodeMap; +import org.simantics.scenegraph.profile.EvaluationContext; +import org.simantics.scenegraph.profile.common.ProfileVariables; +import org.simantics.scenegraph.utils.GeometryUtils; +import org.simantics.scl.runtime.tuple.Tuple5; +import org.simantics.structural.stubs.StructuralResource2; + +import gnu.trove.set.TLongSet; +import gnu.trove.set.hash.TLongHashSet; + +/** + * @author Tuukka Lehtonen + */ +public class TypicalInheritanceStyle extends StyleBase { + + private static final TypicalInheritanceResult NOT_INHERITED = new TypicalInheritanceResult(Boolean.FALSE, null, null, Boolean.FALSE, null); + + private static final Paint PAINT = new Color(128, 128, 128, 64); + private static final Paint PAINT_WITHOUT_SOURCE = new Color(255, 128, 128, 64); + private static final Stroke STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND); + + @Override + public TypicalInheritanceResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException { + DiagramResource DIA = DiagramResource.getInstance(graph); + ModelingResources MOD = ModelingResources.getInstance(graph); + StructuralResource2 STR = StructuralResource2.getInstance(graph); + + boolean templatized = graph.hasStatement(element, MOD.IsTemplatized); + boolean hasElementSource = graph.hasStatement(element, MOD.HasElementSource); + if (templatized) { + if (graph.isInstanceOf(element, DIA.RouteGraphConnection)) { + Collection connectors = graph.getObjects(element, DIA.HasConnector); + Collection routeNodes = graph.getObjects(element, DIA.HasInteriorRouteNode); + TLongHashSet nonTemplatizedConnectors = null; + + // This is needed to make this query result change every time the underlying element changes visually. + Set identifier = new HashSet(connectors.size() + routeNodes.size()); + + for (Resource connector : connectors) { + for (Resource connectedTo : graph.getObjects(connector, STR.Connects)) { + if (!connectedTo.equals(element)) { + AffineTransform at = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, connectedTo, DIA.HasDynamicTransform, false); + identifier.add(at); + + boolean connectedToTemplatized = graph.hasStatement(connectedTo, MOD.IsTemplatized); + if (!connectedToTemplatized) { + if (nonTemplatizedConnectors == null) + nonTemplatizedConnectors = new TLongHashSet(); + nonTemplatizedConnectors.add(connector.getResourceId()); + } + break; + } + } + } + if (!routeNodes.isEmpty()) { + for (Resource routeLine : routeNodes) { + RouteLine rl = Paster.readRouteLine(graph, routeLine); + identifier.add(rl); + } + } + return new TypicalInheritanceResult(templatized, nonTemplatizedConnectors, IdentityAffineTransform.INSTANCE, hasElementSource, identifier); + } else if (graph.isInstanceOf(element, DIA.Monitor)) { + AffineTransform worldTransform = DiagramGraphUtil.getWorldTransform(graph, element); + Resource monitoredComponent = graph.getPossibleObject(element, DIA.HasMonitorComponent); + + if (monitoredComponent != null) { + Resource monitoredElement = graph.getPossibleObject(monitoredComponent, MOD.ComponentToElement); + if (graph.isInstanceOf(monitoredElement, DIA.Connection)) { + Resource tailNode = ConnectionUtil.getConnectionTailNode(graph, monitoredElement); + if (tailNode != null) { + monitoredElement = tailNode; + } + } + + if (monitoredElement != null) { + Resource diagram = graph.syncRequest(new PossibleTypedParent(element, DIA.Diagram)); + if (diagram != null) { + Resource monitoredDiagram = graph.syncRequest(new PossibleTypedParent(monitoredElement, DIA.Diagram)); + if (diagram.equals(monitoredDiagram)) { + AffineTransform monitoredElementWorldTransform = DiagramGraphUtil.getWorldTransform(graph, monitoredElement); + worldTransform.preConcatenate(monitoredElementWorldTransform); + } + } + } + } + + return new TypicalInheritanceResult(templatized, null, worldTransform, hasElementSource, null); + } + + AffineTransform worldTransform = DiagramGraphUtil.getWorldTransform(graph, element); + return new TypicalInheritanceResult(templatized, null, worldTransform, hasElementSource, null); + } + + return NOT_INHERITED; + } + + public void applyStyleForItem(EvaluationContext context, DataNodeMap map, Object item, TypicalInheritanceResult result) { + final INode _node = map.getNode(item); + + if (result != null && Boolean.TRUE.equals(result.isTemplatized())) { + boolean fill = true; + Stroke stroke = null; + ShapeNode node = null; + + if (_node instanceof ParentNode) { + node = ProfileVariables.claimChild(_node, "", "typical", DecorationShapeNode.class, context); + } else { + // Ignore, cannot create decoration. + return; + } + + if (_node instanceof ConnectionNode) { + fill = false; + stroke = STROKE; + } + + Shape shape = null; + IDiagram diagram = context.getConstant(ProfileKeys.DIAGRAM); + if (diagram != null) { + DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class); + if (dem != null) { + IElement element = dem.getElement(diagram, item); + if (element != null) { + SelectionOutline so = element.getElementClass().getAtMostOneItemOfClass(SelectionOutline.class); + if (so != null) { + RouteGraph rg = element.getHint(RouteGraphConnectionClass.KEY_ROUTEGRAPH); + if (rg != null) { + RouteGraph rgc = rg; + TLongSet nonTemplatizedConnectors = result.getNonTemplatizedConnectors(); + if (nonTemplatizedConnectors != null) { + rgc = rg.copy(); + // Must copy the RouteTerminal to an array before + // invoking rgc.remove(RouteTerminal), otherwise + // ConcurrentModificationExceptions will arise. + Collection rtc = rgc.getTerminals(); + if (nonTemplatizedConnectors.size() > (rtc.size() - 2)) { + // Cannot make a RouteGraph any simpler + // than a simple connection between two + // terminals. + // Fall back to highlighting the whole + // connection. + } else { + RouteTerminal[] rts = rtc.toArray(new RouteTerminal[rtc.size()]); + for (RouteTerminal rt : rts) { + Object data = rt.getData(); + if (data instanceof Long) { + if (nonTemplatizedConnectors.contains(((Long) data).longValue())) + rgc.remove(rt); + } + } + } + } + + Path2D path = rgc.getPath2D(); + Stroke connectionStroke = ConnectionSelectionOutline.INSTANCE.resolveStroke(element, ConnectionSelectionOutline.defaultStroke); + shape = connectionStroke.createStrokedShape(path); + } else { + shape = so.getSelectionShape(element); + } + } else { + Rectangle2D rect = ElementUtils.getElementBounds(element); + shape = GeometryUtils.expandRectangle( rect, 0.5 ); + } + } + } + } + + AffineTransform at = result.getWorldTransform(); + if (at != null) + node.setTransform(at); + + node.setZIndex(-1000); + node.setColor(result.hasElementSource() ? PAINT : PAINT_WITHOUT_SOURCE); + node.setFill(fill); + node.setScaleStroke(false); + node.setScaleShape(false); + node.setStroke(stroke); + node.setShape(shape); + } else { + cleanupStyleForNode(context, _node); + } + } + + @Override + protected void cleanupStyleForNode(EvaluationContext context, INode node) { + ProfileVariables.denyChild(node, "*", "typical"); + ProfileVariables.denyChild(node, "", "typical"); + } + +} + +class TypicalInheritanceResult extends Tuple5 { + public TypicalInheritanceResult(Boolean templatized, TLongSet nonTemplatizedConnectors, AffineTransform worldTransform, Boolean hasElementSource, Set queryIdentifier) { + super(templatized, nonTemplatizedConnectors, worldTransform, hasElementSource, queryIdentifier); + } + public boolean isTemplatized() { + return (Boolean) get(0); + } + public TLongSet getNonTemplatizedConnectors() { + return (TLongSet) get(1); + } + public AffineTransform getWorldTransform() { + return (AffineTransform) get(2); + } + public boolean hasElementSource() { + return (Boolean) get(3); + } +}