-/*******************************************************************************\r
- * Copyright (c) 2007, 2016 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- * Semantum Oy - Fixed bug #6364\r
- *******************************************************************************/\r
-package org.simantics.diagram.participant;\r
-\r
-import java.awt.geom.AffineTransform;\r
-import java.util.ArrayDeque;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.Deque;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.ui.IWorkbenchWindow;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.Statement;\r
-import org.simantics.db.VirtualGraph;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.CommentMetadata;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.utils.OrderedSetUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.diagram.content.ConnectionUtil;\r
-import org.simantics.diagram.content.ResourceTerminal;\r
-import org.simantics.diagram.flag.DiagramFlagPreferences;\r
-import org.simantics.diagram.flag.FlagLabelingScheme;\r
-import org.simantics.diagram.flag.FlagUtil;\r
-import org.simantics.diagram.flag.IOTableUtil;\r
-import org.simantics.diagram.flag.IOTablesInfo;\r
-import org.simantics.diagram.flag.Joiner;\r
-import org.simantics.diagram.stubs.DiagramResource;\r
-import org.simantics.diagram.stubs.G2DResource;\r
-import org.simantics.diagram.synchronization.ISynchronizationContext;\r
-import org.simantics.diagram.synchronization.SynchronizationHints;\r
-import org.simantics.diagram.synchronization.graph.AddElement;\r
-import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
-import org.simantics.diagram.synchronization.graph.GraphSynchronizationHints;\r
-import org.simantics.diagram.synchronization.graph.RemoveElement;\r
-import org.simantics.diagram.synchronization.graph.layer.GraphLayerManager;\r
-import org.simantics.diagram.ui.DiagramModelHints;\r
-import org.simantics.g2d.connection.handler.ConnectionHandler;\r
-import org.simantics.g2d.diagram.DiagramHints;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.handler.Topology.Terminal;\r
-import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo;\r
-import org.simantics.g2d.element.ElementClass;\r
-import org.simantics.g2d.element.ElementClasses;\r
-import org.simantics.g2d.element.ElementHints;\r
-import org.simantics.g2d.element.ElementUtils;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.element.IElementClassProvider;\r
-import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
-import org.simantics.g2d.element.impl.Element;\r
-import org.simantics.g2d.elementclass.BranchPoint;\r
-import org.simantics.g2d.elementclass.FlagClass;\r
-import org.simantics.g2d.elementclass.FlagClass.Type;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.modeling.ModelingResources;\r
-import org.simantics.scl.runtime.tuple.Tuple2;\r
-import org.simantics.structural.stubs.StructuralResource2;\r
-import org.simantics.structural2.modelingRules.CPTerminal;\r
-import org.simantics.structural2.modelingRules.ConnectionJudgement;\r
-import org.simantics.structural2.modelingRules.IConnectionPoint;\r
-import org.simantics.structural2.modelingRules.IModelingRules;\r
-import org.simantics.utils.datastructures.Callback;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public class ConnectionBuilder {\r
-\r
- protected static class Connector extends Tuple2 {\r
- public Connector(Resource attachmentRelation, Resource connector) {\r
- super(attachmentRelation, connector);\r
- }\r
- public Resource getAttachment() {\r
- return (Resource) c0;\r
- }\r
- public Resource getConnector() {\r
- return (Resource) c1;\r
- }\r
- }\r
-\r
- protected final IDiagram diagram;\r
- protected final Resource diagramResource;\r
- protected final boolean createFlags;\r
-\r
- protected final ISynchronizationContext ctx;\r
- protected final IElementClassProvider elementClassProvider;\r
- protected final GraphLayerManager layerManager;\r
-\r
- protected ConnectionUtil cu;\r
-\r
- protected Layer0 L0;\r
- protected DiagramResource DIA;\r
- protected StructuralResource2 STR;\r
- protected ModelingResources MOD;\r
-\r
- public ConnectionBuilder(IDiagram diagram) {\r
- this.diagram = diagram;\r
- this.diagramResource = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);\r
- this.createFlags = Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_USE_CONNECTION_FLAGS));\r
-\r
- ctx = diagram.getHint(SynchronizationHints.CONTEXT);\r
- if (ctx != null) {\r
- this.elementClassProvider = ctx.get(SynchronizationHints.ELEMENT_CLASS_PROVIDER);\r
- this.layerManager = ctx.get(GraphSynchronizationHints.GRAPH_LAYER_MANAGER);\r
- } else {\r
- this.elementClassProvider = null;\r
- this.layerManager = null;\r
- }\r
- }\r
-\r
- protected void initializeResources(ReadGraph graph) {\r
- if (this.L0 == null) {\r
- this.L0 = Layer0.getInstance(graph);\r
- this.DIA = DiagramResource.getInstance(graph);\r
- this.STR = StructuralResource2.getInstance(graph);\r
- this.MOD = ModelingResources.getInstance(graph);\r
- }\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param judgment\r
- * @param controlPoints\r
- * @param startTerminal\r
- * @param endTerminal\r
- * @throws DatabaseException\r
- */\r
- public void create(WriteGraph graph, final ConnectionJudgement judgment, Deque<ControlPoint> controlPoints,\r
- TerminalInfo startTerminal, TerminalInfo endTerminal) throws DatabaseException {\r
- this.cu = new ConnectionUtil(graph);\r
- initializeResources(graph);\r
-\r
- final IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);\r
-\r
- final Resource startDisconnectedFlag = getDisconnectedFlag(graph, startTerminal);\r
- final Resource endDisconnectedFlag = getDisconnectedFlag(graph, endTerminal);\r
- if (startDisconnectedFlag != null || endDisconnectedFlag != null) {\r
- if (startDisconnectedFlag != null && endDisconnectedFlag != null) {\r
-\r
- // Ask the user which operation to perform:\r
- // a) connect the disconnected flags together with a connection join\r
- // b) join the flags into a single connection\r
-\r
- final VirtualGraph graphProvider = graph.getProvider();\r
- final Session session = graph.getSession();\r
-\r
- PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();\r
- if (window == null)\r
- return;\r
- MessageDialog dialog = new MessageDialog(window.getShell(), "Connect or Join Flags?", null,\r
- "Connect flags together or join them visually into a connection?",\r
- MessageDialog.QUESTION_WITH_CANCEL, new String[] { "Connect Flags", "Join Flags",\r
- "Cancel" }, 0) {\r
- {\r
- setShellStyle(getShellStyle() | SWT.SHEET);\r
- }\r
- };\r
- final int choice = dialog.open();\r
-\r
- if (choice != 2 && choice != SWT.DEFAULT) {\r
- session.asyncRequest(new WriteRequest(graphProvider) {\r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- graph.markUndoPoint();\r
- switch (choice) {\r
- case 0: {\r
- Resource join = FlagUtil.join(graph, startDisconnectedFlag, endDisconnectedFlag);\r
- FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph);\r
- String commonLabel = scheme.generateLabel(graph, diagramResource);\r
- graph.claimLiteral(startDisconnectedFlag, L0.HasLabel, DIA.FlagLabel, commonLabel);\r
- graph.claimLiteral(endDisconnectedFlag, L0.HasLabel, DIA.FlagLabel, commonLabel);\r
-\r
- // Set connection type according to modeling rules\r
- setJoinedConnectionTypes(graph, modelingRules, judgment, join);\r
-\r
- // Add comment to change set.\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Connected flags"));\r
-\r
- return;\r
- }\r
- case 1: {\r
- // First connect the flags together\r
- Resource join = FlagUtil.join(graph, startDisconnectedFlag, endDisconnectedFlag);\r
-\r
- // Set connection type according to modeling rules\r
- setJoinedConnectionTypes(graph, modelingRules, judgment, join);\r
-\r
- // Join the flags into a direct connection\r
- new Joiner(graph).joinLocal(graph, Arrays.asList(startDisconnectedFlag, endDisconnectedFlag));\r
-\r
- // Add comment to change set.\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Joined flags"));\r
-\r
- return;\r
- }\r
- }\r
- }\r
- }, new Callback<DatabaseException>() {\r
- @Override\r
- public void run(DatabaseException e) {\r
- if (e != null)\r
- ErrorLogger.defaultLogError(e);\r
- }\r
- });\r
- }\r
- }\r
- });\r
-\r
- return;\r
- }\r
-\r
- TerminalInfo normalTerminal = null;\r
- Resource flagToRemove = null;\r
- Resource connection = null;\r
- if (startDisconnectedFlag != null) {\r
- flagToRemove = startDisconnectedFlag;\r
- normalTerminal = endTerminal;\r
- connection = attachedToExistingConnection(graph, startTerminal);\r
- }\r
- if (endDisconnectedFlag != null) {\r
- flagToRemove = endDisconnectedFlag;\r
- normalTerminal = startTerminal;\r
- connection = attachedToExistingConnection(graph, endTerminal);\r
- }\r
- if (connection != null) {\r
- // OK, continuing a connection from an existing disconnected flag.\r
-\r
- // STEPS TO PERFORM:\r
- // 1. remove flag\r
- // 2. connect normal terminal directly to the existing connection\r
- Statement stm = graph.getSingleStatement(flagToRemove, STR.IsConnectedTo);\r
- Collection<Resource> areConnecteds = graph.getObjects(stm.getObject(), DIA.AreConnected);\r
-\r
- // Remove statement to connection connector before removing flag\r
- // to prevent removal of connector and the connection.\r
- graph.deny(stm);\r
- new RemoveElement((Resource)diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE), flagToRemove).perform(graph);\r
-\r
- // Disconnect the connector from the connection and create a\r
- // new connector for the element terminal.\r
- cu.removeConnectionPart(stm.getObject());\r
- Connector newConnector = createConnectorForNode(graph, connection,\r
- (Resource) ElementUtils.getObject(normalTerminal.e), normalTerminal.t,\r
- startDisconnectedFlag != null ? EdgeEnd.End : EdgeEnd.Begin, judgment);\r
-\r
- for (Resource areConnected : areConnecteds)\r
- graph.claim(newConnector.getConnector(), DIA.AreConnected, areConnected);\r
-\r
- if (modelingRules != null && judgment.connectionType != null)\r
- modelingRules.setConnectionType(graph, connection, judgment.connectionType);\r
-\r
- // Add comment to change set.\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Joined flags"));\r
- graph.markUndoPoint();\r
- this.cu = null;\r
- return;\r
- }\r
- }\r
-\r
- // 1. Get diagram connection to construct.\r
- Resource connection = getOrCreateConnection(graph, startTerminal, endTerminal);\r
-\r
- // 1.1 Give running name to connection and increment the counter attached to the diagram.\r
- AddElement.claimFreshElementName(graph, diagramResource, connection);\r
-\r
- // 2. Add branch points\r
- // 3. Create edges between branch points.\r
- List<Pair<ControlPoint, Resource>> bps = Collections.emptyList();\r
- Resource firstBranchPoint = null;\r
- Resource lastBranchPoint = null;\r
- if (!isRouteGraphConnection(graph, connection)) {\r
- bps = createBranchPoints(graph, connection, controlPoints);\r
- if (!bps.isEmpty()) {\r
- Iterator<Pair<ControlPoint, Resource>> it = bps.iterator();\r
- Pair<ControlPoint, Resource> prev = it.next();\r
- firstBranchPoint = prev.second;\r
- while (it.hasNext()) {\r
- Pair<ControlPoint, Resource> next = it.next();\r
- cu.connect(prev.second, next.second);\r
- prev = next;\r
- }\r
- lastBranchPoint = prev.second;\r
- }\r
- }\r
-\r
- // 4. Connect start/end terminals if those exist.\r
- // If first/lastBranchPoint != null, connect to those.\r
- // Otherwise connect the start/end terminals together.\r
- Connector startConnector = null;\r
- Connector endConnector = null;\r
- IElement startFlag = null;\r
- IElement endFlag = null;\r
-\r
- //FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph);\r
-\r
- if (startTerminal != null && endTerminal != null) {\r
- Resource startAttachment = chooseAttachmentRelationForNode(graph, connection, startTerminal, judgment);\r
- Resource endAttachment = chooseAttachmentRelationForNode(graph, connection, endTerminal, judgment);\r
- Pair<Resource, Resource> attachments = resolveEndAttachments(graph, startAttachment, endAttachment);\r
- startConnector = createConnectorForNodeWithAttachment(graph, connection, startTerminal, attachments.first);\r
- endConnector = createConnectorForNodeWithAttachment(graph, connection, endTerminal, attachments.second);\r
- } else if (startTerminal != null) {\r
- startConnector = createConnectorForNode(graph, connection, startTerminal, EdgeEnd.Begin, judgment);\r
- if (createFlags) {\r
- EdgeEnd flagEnd = cu.toEdgeEnd( cu.getAttachmentRelationForConnector(startConnector.getConnector()), EdgeEnd.End ).other();\r
- endFlag = createFlag(graph, connection, flagEnd, controlPoints.getLast(), FlagClass.Type.Out,\r
- //scheme.generateLabel(graph, diagramResource));\r
- null);\r
- endConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(endFlag),\r
- ElementUtils.getSingleTerminal(endFlag), flagEnd, judgment);\r
- }\r
- } else if (endTerminal != null) {\r
- endConnector = createConnectorForNode(graph, connection, endTerminal, EdgeEnd.End, judgment);\r
- if (createFlags) {\r
- EdgeEnd flagEnd = cu.toEdgeEnd( cu.getAttachmentRelationForConnector(endConnector.getConnector()), EdgeEnd.Begin ).other();\r
- startFlag = createFlag(graph, connection, flagEnd, controlPoints.getFirst(), FlagClass.Type.In,\r
- //scheme.generateLabel(graph, diagramResource));\r
- null);\r
- startConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(startFlag),\r
- ElementUtils.getSingleTerminal(startFlag), flagEnd, judgment);\r
- }\r
- } else if (createFlags) {\r
- startFlag = createFlag(graph, connection, EdgeEnd.Begin, controlPoints.getFirst(), FlagClass.Type.In,\r
- //scheme.generateLabel(graph, diagramResource));\r
- null);\r
- startConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(startFlag),\r
- ElementUtils.getSingleTerminal(startFlag), EdgeEnd.Begin, judgment);\r
-\r
- endFlag = createFlag(graph, connection, EdgeEnd.End, controlPoints.getLast(), FlagClass.Type.Out,\r
- //scheme.generateLabel(graph, diagramResource));\r
- null);\r
- endConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(endFlag),\r
- ElementUtils.getSingleTerminal(endFlag), EdgeEnd.End, judgment);\r
- }\r
-\r
- if (firstBranchPoint == null || lastBranchPoint == null) {\r
- cu.connect(startConnector.getConnector(), endConnector.getConnector());\r
- } else {\r
- cu.connect(startConnector.getConnector(), firstBranchPoint);\r
- cu.connect(lastBranchPoint, endConnector.getConnector());\r
- }\r
-\r
- // 5. Finally, set connection type according to modeling rules\r
- if (judgment.connectionType != null && modelingRules != null)\r
- modelingRules.setConnectionType(graph, connection, judgment.connectionType);\r
-\r
- // 5.1 Verify created flag types\r
- if (startFlag != null)\r
- verifyFlagType(graph, modelingRules, startFlag);\r
- if (endFlag != null)\r
- verifyFlagType(graph, modelingRules, endFlag);\r
-\r
- // 5.2 Write ConnectionMappingSpecification to connector if necessary\r
- writeConnectionMappingSpecification(graph, startTerminal, startConnector, judgment.connectionType);\r
- writeConnectionMappingSpecification(graph, endTerminal, endConnector, judgment.connectionType);\r
-\r
- // 6. Add comment to change set.\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Added connection " + connection));\r
- graph.markUndoPoint();\r
- this.cu = null;\r
- }\r
-\r
- private boolean writeConnectionMappingSpecification(WriteGraph graph, TerminalInfo terminal, Connector connector, Resource connectionType)\r
- throws DatabaseException {\r
- Resource diagramConnRel = getConnectionRelation(graph, terminal);\r
- if (diagramConnRel == null)\r
- return false;\r
- Resource connRel = graph.getPossibleObject(diagramConnRel, MOD.DiagramConnectionRelationToConnectionRelation);\r
- if (connRel == null || !graph.hasStatement(connRel, MOD.NeedsConnectionMappingSpecification))\r
- return false;\r
- Resource mappingSpecification = graph.getPossibleObject(connectionType, MOD.ConnectionTypeToConnectionMappingSpecification);\r
- if (mappingSpecification == null)\r
- return false;\r
- graph.claim(connector.getConnector(), MOD.HasConnectionMappingSpecification, null, mappingSpecification);\r
- return true;\r
- }\r
-\r
- private static Resource getConnectionRelation(ReadGraph graph, TerminalInfo ti) throws DatabaseException {\r
- if (ti != null && ti.t instanceof ResourceTerminal) {\r
- Resource t = ((ResourceTerminal) ti.t).getResource();\r
- Resource bindingRelation = DiagramGraphUtil.getConnectionPointOfTerminal(graph, t);\r
- return bindingRelation;\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param startAttachment\r
- * @param endAttachment\r
- * @return\r
- * @throws DatabaseException \r
- */\r
- protected Pair<Resource, Resource> resolveEndAttachments(WriteGraph graph,\r
- Resource startAttachment, Resource endAttachment) throws DatabaseException {\r
- if (startAttachment != null && endAttachment != null)\r
- return Pair.make(startAttachment, endAttachment);\r
-\r
- if (startAttachment != null && endAttachment == null)\r
- return Pair.make(startAttachment, getInverseAttachment(graph, startAttachment, DIA.HasArrowConnector));\r
- if (startAttachment == null && endAttachment != null)\r
- return Pair.make(getInverseAttachment(graph, endAttachment, DIA.HasPlainConnector), endAttachment);\r
-\r
- return Pair.make(DIA.HasPlainConnector, DIA.HasArrowConnector);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param attachment\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- protected Resource getInverseAttachment(ReadGraph graph, Resource attachment, Resource defaultValue) throws DatabaseException {\r
- Resource inverse = attachment != null ? graph.getPossibleObject(attachment, DIA.HasInverseAttachment) : defaultValue;\r
- return inverse != null ? inverse : defaultValue;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param modelingRules\r
- * @param flagElement\r
- * @throws DatabaseException\r
- */\r
- protected void verifyFlagType(WriteGraph graph, IModelingRules modelingRules, IElement flagElement) throws DatabaseException {\r
- if (modelingRules != null) {\r
- Resource flag = flagElement.getHint(ElementHints.KEY_OBJECT);\r
- FlagClass.Type flagType = flagElement.getHint(FlagClass.KEY_FLAG_TYPE);\r
- FlagUtil.verifyFlagType(graph, modelingRules, flag, flagType);\r
- }\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param judgment\r
- * @param connection\r
- * @param attachToLine\r
- * @param controlPoints\r
- * @param endTerminal\r
- * @return the DIA.Connector instance created for attaching the connection\r
- * to the specified end terminal\r
- * @throws DatabaseException\r
- */\r
- public Pair<Resource, Resource> attachToRouteGraph(\r
- WriteGraph graph,\r
- ConnectionJudgement judgment,\r
- Resource attachToConnection,\r
- Resource attachToLine,\r
- Deque<ControlPoint> controlPoints,\r
- TerminalInfo endTerminal)\r
- throws DatabaseException\r
- {\r
- initializeResources(graph);\r
- this.cu = new ConnectionUtil(graph);\r
- try {\r
- Resource endElement = endTerminal != null ? ElementUtils.getObject(endTerminal.e) : null;\r
- if (endElement != null\r
- && graph.isInstanceOf(endElement, DIA.Flag)\r
- && FlagUtil.isDisconnected(graph, endElement))\r
- {\r
- // Connection ends in an existing but disconnected flag that\r
- // should be all right to connect to because the connection\r
- // judgment implies it makes a valid connection.\r
- // Check that we are attaching the connection to an existing\r
- // disconnected flag that is however attached to a connection.\r
- Resource endTerminalConnection = ConnectionBuilder.attachedToExistingConnection(graph, endTerminal);\r
- if (endTerminalConnection != null) {\r
- attachConnectionToFlag(graph, judgment, attachToConnection, attachToLine, controlPoints, endTerminal);\r
- return null;\r
- }\r
- }\r
-\r
- Connector endConnector = null;\r
- if (endTerminal != null) {\r
- endConnector = createConnectorForNode(graph, attachToConnection, endTerminal, EdgeEnd.End, judgment);\r
- } else if (createFlags) {\r
- IElement endFlag = createFlag(graph, attachToConnection, EdgeEnd.End, controlPoints.getLast(), FlagClass.Type.Out, null);\r
- endConnector = createConnectorForNode(graph, attachToConnection, (Resource) ElementUtils.getObject(endFlag),\r
- ElementUtils.getSingleTerminal(endFlag), EdgeEnd.End, judgment);\r
- }\r
-\r
- cu.connect(attachToLine, endConnector.getConnector());\r
-\r
- IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);\r
- if (judgment.connectionType != null && modelingRules != null) {\r
- modelingRules.setConnectionType(graph, attachToConnection, judgment.connectionType);\r
- }\r
-\r
- writeConnectionMappingSpecification(graph, endTerminal, endConnector, judgment.connectionType);\r
-\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Branched connection " + attachToConnection));\r
-\r
- return Pair.make(endConnector.getAttachment(), endConnector.getConnector());\r
- } finally {\r
- this.cu = null;\r
- }\r
- }\r
-\r
- protected void attachConnectionToFlag(\r
- WriteGraph graph,\r
- ConnectionJudgement judgment,\r
- Resource attachToConnection,\r
- Resource attachToLine,\r
- Deque<ControlPoint> controlPoints,\r
- TerminalInfo toFlag)\r
- throws DatabaseException\r
- {\r
- // Attaching attachedConnection to an existing disconnected flag that is\r
- // however attached to a connection.\r
- // STEPS:\r
- // 1. remove flag and its connector\r
- // 2. attach the two connections together by moving the route nodes\r
- // of the removed flag-side connection under the remaining connection\r
- // and ensuring that the route node chain will be valid after the\r
- // switch. In a chain route lines, each line must have an opposite\r
- // direction compared to the lines connected to it.\r
- Resource flagToRemove = ElementUtils.getObject(toFlag.e);\r
- Statement flagToConnector = graph.getSingleStatement(flagToRemove, STR.IsConnectedTo);\r
- Resource flagConnector = flagToConnector.getObject();\r
- Resource flagConnection = ConnectionUtil.getConnection(graph, flagConnector);\r
- Collection<Resource> flagRouteNodes = graph.getObjects(flagConnector, DIA.AreConnected);\r
-\r
- Resource connectionToKeep = attachToConnection;\r
- Resource connectionToRemove = flagConnection;\r
- if (!connectionToKeep.equals(connectionToRemove)) {\r
- Resource hasElementToComponent1 = graph.getPossibleObject(attachToConnection, MOD.ElementToComponent);\r
- Resource hasElementToComponent2 = graph.getPossibleObject(flagConnection, MOD.ElementToComponent);\r
- Type flagType = FlagUtil.getFlagType(graph, flagToRemove);\r
- if (hasElementToComponent1 != null && hasElementToComponent2 != null)\r
- throw new UnsupportedOperationException(\r
- "Both attached connection " + attachToConnection + " and flag connection " + flagConnection\r
- + " have mapped components, can't decide which connection to remove in join operation");\r
- if (hasElementToComponent2 != null || flagType == Type.Out) {\r
- connectionToKeep = flagConnection;\r
- connectionToRemove = attachToConnection;\r
- }\r
- }\r
-\r
- // Remove flag and its connector.\r
- graph.deny(flagToConnector);\r
- new RemoveElement((Resource)diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE), flagToRemove).perform(graph);\r
- cu.removeConnectionPart(flagConnector);\r
-\r
- // Attached routeline must have opposite direction than the line\r
- // attached to in order for the connection to be valid.\r
- Boolean attachingToHorizontalLine = graph.getPossibleRelatedValue(attachToLine, DIA.IsHorizontal, Bindings.BOOLEAN);\r
- if (attachingToHorizontalLine != null) {\r
- for (Resource routeNode : flagRouteNodes) {\r
- Collection<Resource> routeNodesToAttachTo = removeUntilOrientedRouteline(graph, !attachingToHorizontalLine, routeNode);\r
- for (Resource rn : routeNodesToAttachTo)\r
- cu.connect(attachToLine, rn);\r
- }\r
- }\r
-\r
- moveStatements(graph, connectionToRemove, connectionToKeep, DIA.HasInteriorRouteNode);\r
- moveStatements(graph, connectionToRemove, connectionToKeep, DIA.HasConnector);\r
-\r
- // Remove obsolete connection\r
- if (!connectionToKeep.equals(connectionToRemove))\r
- cu.removeConnection(connectionToRemove);\r
-\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Joined connection to disconnected flag"));\r
- }\r
-\r
- private void moveStatements(WriteGraph graph, Resource source, Resource target, Resource movedRelation) throws DatabaseException {\r
- if (!source.equals(target)) {\r
- for (Statement s : graph.getStatements(source, movedRelation)) {\r
- graph.deny(s);\r
- graph.claim(target, s.getPredicate(), s.getObject());\r
- }\r
- }\r
- }\r
-\r
- private Collection<Resource> removeUntilOrientedRouteline(WriteGraph graph, boolean expectedOrientation, Resource routeNode) throws DatabaseException {\r
- List<Resource> result = new ArrayList<>(2);\r
- Deque<Resource> work = new ArrayDeque<>(2);\r
- work.addLast(routeNode);\r
- while (!work.isEmpty()) {\r
- Resource rn = work.removeFirst();\r
- if (graph.isInstanceOf(rn, DIA.RouteLine)) {\r
- Boolean isHorizontal = graph.getPossibleRelatedValue(rn, DIA.IsHorizontal, Bindings.BOOLEAN);\r
- if (isHorizontal != null && expectedOrientation != isHorizontal) {\r
- for (Resource rnn : graph.getObjects(rn, DIA.AreConnected))\r
- work.addLast(rnn);\r
- cu.removeConnectionPart(rn);\r
- continue;\r
- }\r
- }\r
- result.add(rn);\r
- }\r
- return result;\r
- }\r
-\r
- protected boolean isRouteGraphConnection(ReadGraph graph, Resource connection) throws DatabaseException {\r
- initializeResources(graph);\r
- return graph.isInstanceOf(connection, DIA.RouteGraphConnection);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param ti\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- public static Resource attachedToExistingConnection(ReadGraph graph, TerminalInfo ti) throws DatabaseException {\r
- Object obj = ElementUtils.getObject(ti.e);\r
- Resource cp = DiagramGraphUtil.getConnectionPointOfTerminal(graph, ti.t);\r
- if (obj instanceof Resource && cp != null) {\r
- Resource e = (Resource) obj;\r
- for (Resource connector : graph.getObjects(e, cp)) {\r
- Resource connection = ConnectionUtil.tryGetConnection(graph, connector);\r
- if (connection != null)\r
- return connection;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param tis\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- public Resource getOrCreateConnection(ReadGraph graph, TerminalInfo... tis) throws DatabaseException {\r
- // Resolve if adding to existing connection.\r
- Resource connection = null;\r
- for (TerminalInfo ti : tis) {\r
- connection = getExistingConnection(graph, ti);\r
- if (connection != null)\r
- break;\r
- }\r
-\r
- if (connection == null) {\r
- // No existing connection, create new.\r
- ElementClass connectionClass = elementClassProvider.get(ElementClasses.CONNECTION);\r
- Resource connectionClassResource = ElementUtils.checkedAdapt(connectionClass, Resource.class);\r
- connection = cu.newConnection(diagramResource, connectionClassResource);\r
- }\r
-\r
- return connection;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param controlPoints\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- public List<Pair<ControlPoint, Resource>> createBranchPoints(WriteGraph graph, Resource connection,\r
- Collection<ControlPoint> controlPoints) throws DatabaseException {\r
- List<Pair<ControlPoint, Resource>> bps = new ArrayList<Pair<ControlPoint, Resource>>(controlPoints.size());\r
- for(ControlPoint cp : controlPoints) {\r
- if (cp.isAttachedToTerminal())\r
- // Terminal attachments do not need branch points.\r
- continue;\r
-\r
- Resource bp = cu.newBranchPoint(connection,\r
- AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY()),\r
- cp.getDirection());\r
- bps.add(Pair.make(cp, bp));\r
- }\r
- return bps;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param ti\r
- * @param end\r
- * @param judgment\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- protected Resource chooseAttachmentRelationForNode(ReadGraph graph,\r
- Resource connection, TerminalInfo ti, ConnectionJudgement judgment)\r
- throws DatabaseException {\r
- Resource node = (Resource) ElementUtils.getObject(ti.e);\r
- return chooseAttachmentRelationForNode(graph, connection, node, ti.t, judgment);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param element\r
- * @param terminal\r
- * @param end\r
- * @param judgment\r
- * @return the calculated attachment relation or <code>null</code> if the\r
- * result is ambiguous\r
- * @throws DatabaseException\r
- */\r
- protected Resource chooseAttachmentRelationForNode(ReadGraph graph,\r
- Resource connection, Resource element, Terminal terminal,\r
- ConnectionJudgement judgment) throws DatabaseException {\r
- IConnectionPoint cp = ConnectionUtil.toConnectionPoint(graph, element, terminal);\r
- CPTerminal cpt = (cp instanceof CPTerminal) ? (CPTerminal) cp : null;\r
- Resource attachment = judgment.attachmentRelations.get(graph, cpt);\r
- return attachment;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param ti\r
- * @param connectTo resource to connect the new connector to if not\r
- * <code>null</code>\r
- * @param judgment\r
- * @return <used attachment relation, the new DIA.Connector instance>. The\r
- * attachment relation is <code>null</code> if it was chosen based\r
- * on EdgeEnd instead of being defined\r
- * @throws DatabaseException\r
- */\r
- protected Connector createConnectorForNode(WriteGraph graph, Resource connection, TerminalInfo ti, EdgeEnd end,\r
- ConnectionJudgement judgment) throws DatabaseException {\r
- Resource node = (Resource) ElementUtils.getObject(ti.e);\r
- return createConnectorForNode(graph, connection, node, ti.t, end, judgment);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param element\r
- * @param terminal\r
- * @param end\r
- * @param connectTo\r
- * @param judgment\r
- * @return <used attachment relation, the new DIA.Connector instance>. The\r
- * attachment relation is <code>null</code> if it was chosen based\r
- * on EdgeEnd instead of being defined\r
- * @throws DatabaseException\r
- */\r
- protected Connector createConnectorForNode(WriteGraph graph, Resource connection, Resource element, Terminal terminal,\r
- EdgeEnd end, ConnectionJudgement judgment) throws DatabaseException {\r
- IConnectionPoint cp = ConnectionUtil.toConnectionPoint(graph, element, terminal);\r
- CPTerminal cpt = (cp instanceof CPTerminal) ? (CPTerminal) cp : null;\r
- Resource attachment = judgment.attachmentRelations.get(graph, cpt);\r
- if (attachment == null)\r
- attachment = cu.toHasConnectorRelation(end);\r
- Resource connector = cu.getOrCreateConnector(connection, element, terminal, end, attachment);\r
- return new Connector(attachment, connector);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param ti\r
- * @param attachment\r
- * @return <used attachment relation, the new DIA.Connector instance>\r
- * @throws DatabaseException\r
- */\r
- protected Connector createConnectorForNodeWithAttachment(WriteGraph graph,\r
- Resource connection, TerminalInfo ti, Resource attachment)\r
- throws DatabaseException {\r
- Resource node = (Resource) ElementUtils.getObject(ti.e);\r
- return createConnectorForNodeWithAttachment(graph, connection, node, ti.t, attachment);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param element\r
- * @param terminal\r
- * @param attachment\r
- * @return <used attachment relation, the new DIA.Connector instance>\r
- * @throws DatabaseException\r
- */\r
- protected Connector createConnectorForNodeWithAttachment(WriteGraph graph,\r
- Resource connection, Resource element, Terminal terminal,\r
- Resource attachment) throws DatabaseException {\r
- Resource connector = cu.getOrCreateConnector(connection, element, terminal, null, attachment);\r
- return new Connector(attachment, connector);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param connection\r
- * @param end\r
- * @param cp\r
- * @param type\r
- * @param label <code>null</code> to leave flag without label\r
- * @return an element describing the new created flag resource\r
- * @throws DatabaseException\r
- */\r
- public IElement createFlag(WriteGraph graph, Resource connection, EdgeEnd end, ControlPoint cp,\r
- FlagClass.Type type, String label) throws DatabaseException {\r
- ElementClass flagClass = elementClassProvider.get(ElementClasses.FLAG);\r
- IElement flagElement = Element.spawnNew(flagClass);\r
- Resource flagClassResource = ElementUtils.checkedAdapt(flagClass, Resource.class);\r
-\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- G2DResource G2D = G2DResource.getInstance(graph);\r
- DiagramResource DIA = DiagramResource.getInstance(graph);\r
-\r
- Resource flag = graph.newResource();\r
- graph.claim(flag, L0.InstanceOf, null, flagClassResource);\r
- flagElement.setHint(ElementHints.KEY_OBJECT, flag);\r
-\r
- OrderedSetUtils.add(graph, diagramResource, flag);\r
-\r
- AffineTransform at = AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY());\r
- flagElement.setHint(ElementHints.KEY_TRANSFORM, at);\r
- double[] matrix = new double[6];\r
- at.getMatrix(matrix);\r
- graph.claimLiteral(flag, DIA.HasTransform, G2D.Transform, matrix);\r
-\r
- flagElement.setHint(FlagClass.KEY_FLAG_TYPE, type);\r
- graph.claim(flag, DIA.HasFlagType, null, DiagramGraphUtil.toFlagTypeResource(DIA, type));\r
- if (label != null)\r
- graph.claimLiteral(flag, L0.HasLabel, DIA.FlagLabel, label, Bindings.STRING);\r
-\r
- // Give running name to flag and increment the counter attached to the diagram.\r
- AddElement.claimFreshElementName(graph, diagramResource, flag);\r
-\r
- // Make the diagram consist of the new element\r
- graph.claim(diagramResource, L0.ConsistsOf, flag);\r
-\r
- // Put the element on all the currently active layers if possible.\r
- if (layerManager != null) {\r
- layerManager.removeFromAllLayers(graph, flag);\r
- layerManager.putElementOnVisibleLayers(diagram, graph, flag);\r
- }\r
- \r
- // Add flag to possible IO table\r
- IOTablesInfo ioTablesInfo = IOTableUtil.getIOTablesInfo(graph, \r
- (Resource)diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE));\r
- ioTablesInfo.updateBinding(graph, DIA, flag, at.getTranslateX(), at.getTranslateY());\r
- \r
- return flagElement;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param ti\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- protected static Resource getExistingConnection(ReadGraph graph, TerminalInfo ti) throws DatabaseException {\r
- if (ti != null) {\r
- if (isConnection(ti.e)) {\r
- Object obj = ElementUtils.getObject(ti.e);\r
- if (obj instanceof Resource) {\r
- Resource c = (Resource) obj;\r
- return graph.isInstanceOf(c, DiagramResource.getInstance(graph).Connection) ? c : null;\r
- }\r
- } else if (isBranchPoint(ti.e)) {\r
- Object obj = ElementUtils.getObject(ti.e);\r
- if (obj instanceof Resource) {\r
- return ConnectionUtil.tryGetConnection(graph, (Resource) obj);\r
- }\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- protected static boolean isConnection(IElement e) {\r
- return e.getElementClass().containsClass(ConnectionHandler.class);\r
- }\r
-\r
- /**\r
- * @param e\r
- * @return\r
- */\r
- protected static boolean isBranchPoint(IElement e) {\r
- return e.getElementClass().containsClass(BranchPoint.class);\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param terminal\r
- * @return\r
- * @throws DatabaseException \r
- */\r
- protected static Resource getDisconnectedFlag(ReadGraph graph, TerminalInfo terminal) throws DatabaseException {\r
- if (terminal != null) {\r
- Object obj = ElementUtils.getObject(terminal.e);\r
- if (obj instanceof Resource) {\r
- Resource flag = (Resource) obj;\r
- if (graph.isInstanceOf(flag, DiagramResource.getInstance(graph).Flag)\r
- && FlagUtil.isDisconnected(graph, flag))\r
- return flag;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param modelingRules\r
- * @param judgment\r
- * @param join\r
- * @throws DatabaseException\r
- */\r
- protected static void setJoinedConnectionTypes(WriteGraph graph, IModelingRules modelingRules,\r
- ConnectionJudgement judgment, Resource join) throws DatabaseException {\r
- if (modelingRules != null && judgment != null && judgment.connectionType != null) {\r
- DiagramResource DIA = DiagramResource.getInstance(graph);\r
- StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
- List<Resource> connections = new ArrayList<Resource>(2);\r
- for (Resource flag : graph.getObjects(join, DIA.FlagIsJoinedBy)) {\r
- for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {\r
- Resource connection = ConnectionUtil.tryGetConnection(graph, connector);\r
- if (connection != null)\r
- connections.add(connection);\r
- }\r
- }\r
- for (Resource connection : connections)\r
- modelingRules.setConnectionType(graph, connection, judgment.connectionType);\r
- }\r
- }\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - Fixed bug #6364
+ *******************************************************************************/
+package org.simantics.diagram.participant;
+
+import java.awt.geom.AffineTransform;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.Statement;
+import org.simantics.db.VirtualGraph;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.CommentMetadata;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.utils.OrderedSetUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.diagram.content.ConnectionUtil;
+import org.simantics.diagram.content.ResourceTerminal;
+import org.simantics.diagram.flag.DiagramFlagPreferences;
+import org.simantics.diagram.flag.FlagLabelingScheme;
+import org.simantics.diagram.flag.FlagUtil;
+import org.simantics.diagram.flag.IOTableUtil;
+import org.simantics.diagram.flag.IOTablesInfo;
+import org.simantics.diagram.flag.Joiner;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.stubs.G2DResource;
+import org.simantics.diagram.synchronization.ISynchronizationContext;
+import org.simantics.diagram.synchronization.SynchronizationHints;
+import org.simantics.diagram.synchronization.graph.AddElement;
+import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
+import org.simantics.diagram.synchronization.graph.GraphSynchronizationHints;
+import org.simantics.diagram.synchronization.graph.RemoveElement;
+import org.simantics.diagram.synchronization.graph.layer.GraphLayerManager;
+import org.simantics.diagram.ui.DiagramModelHints;
+import org.simantics.g2d.connection.handler.ConnectionHandler;
+import org.simantics.g2d.diagram.DiagramHints;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.Topology.Terminal;
+import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo;
+import org.simantics.g2d.element.ElementClass;
+import org.simantics.g2d.element.ElementClasses;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.IElementClassProvider;
+import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
+import org.simantics.g2d.element.impl.Element;
+import org.simantics.g2d.elementclass.BranchPoint;
+import org.simantics.g2d.elementclass.FlagClass;
+import org.simantics.g2d.elementclass.FlagClass.Type;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.scl.runtime.tuple.Tuple2;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.structural2.modelingRules.CPTerminal;
+import org.simantics.structural2.modelingRules.ConnectionJudgement;
+import org.simantics.structural2.modelingRules.IConnectionPoint;
+import org.simantics.structural2.modelingRules.IModelingRules;
+import org.simantics.utils.datastructures.Callback;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.ui.ErrorLogger;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class ConnectionBuilder {
+
+ protected static class Connector extends Tuple2 {
+ public Connector(Resource attachmentRelation, Resource connector) {
+ super(attachmentRelation, connector);
+ }
+ public Resource getAttachment() {
+ return (Resource) c0;
+ }
+ public Resource getConnector() {
+ return (Resource) c1;
+ }
+ }
+
+ protected final IDiagram diagram;
+ protected final Resource diagramResource;
+ protected final boolean createFlags;
+
+ protected final ISynchronizationContext ctx;
+ protected final IElementClassProvider elementClassProvider;
+ protected final GraphLayerManager layerManager;
+
+ protected ConnectionUtil cu;
+
+ protected Layer0 L0;
+ protected DiagramResource DIA;
+ protected StructuralResource2 STR;
+ protected ModelingResources MOD;
+
+ public ConnectionBuilder(IDiagram diagram) {
+ this.diagram = diagram;
+ this.diagramResource = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
+ this.createFlags = Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_USE_CONNECTION_FLAGS));
+
+ ctx = diagram.getHint(SynchronizationHints.CONTEXT);
+ if (ctx != null) {
+ this.elementClassProvider = ctx.get(SynchronizationHints.ELEMENT_CLASS_PROVIDER);
+ this.layerManager = ctx.get(GraphSynchronizationHints.GRAPH_LAYER_MANAGER);
+ } else {
+ this.elementClassProvider = null;
+ this.layerManager = null;
+ }
+ }
+
+ protected void initializeResources(ReadGraph graph) {
+ if (this.L0 == null) {
+ this.L0 = Layer0.getInstance(graph);
+ this.DIA = DiagramResource.getInstance(graph);
+ this.STR = StructuralResource2.getInstance(graph);
+ this.MOD = ModelingResources.getInstance(graph);
+ }
+ }
+
+ /**
+ * @param graph
+ * @param judgment
+ * @param controlPoints
+ * @param startTerminal
+ * @param endTerminal
+ * @throws DatabaseException
+ */
+ public void create(WriteGraph graph, final ConnectionJudgement judgment, Deque<ControlPoint> controlPoints,
+ TerminalInfo startTerminal, TerminalInfo endTerminal) throws DatabaseException {
+ this.cu = new ConnectionUtil(graph);
+ initializeResources(graph);
+
+ final IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);
+
+ final Resource startDisconnectedFlag = getDisconnectedFlag(graph, startTerminal);
+ final Resource endDisconnectedFlag = getDisconnectedFlag(graph, endTerminal);
+ if (startDisconnectedFlag != null || endDisconnectedFlag != null) {
+ if (startDisconnectedFlag != null && endDisconnectedFlag != null) {
+
+ // Ask the user which operation to perform:
+ // a) connect the disconnected flags together with a connection join
+ // b) join the flags into a single connection
+
+ final VirtualGraph graphProvider = graph.getProvider();
+ final Session session = graph.getSession();
+
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null)
+ return;
+ MessageDialog dialog = new MessageDialog(window.getShell(), "Connect or Join Flags?", null,
+ "Connect flags together or join them visually into a connection?",
+ MessageDialog.QUESTION_WITH_CANCEL, new String[] { "Connect Flags", "Join Flags",
+ "Cancel" }, 0) {
+ {
+ setShellStyle(getShellStyle() | SWT.SHEET);
+ }
+ };
+ final int choice = dialog.open();
+
+ if (choice != 2 && choice != SWT.DEFAULT) {
+ session.asyncRequest(new WriteRequest(graphProvider) {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ graph.markUndoPoint();
+ switch (choice) {
+ case 0: {
+ Resource join = FlagUtil.join(graph, startDisconnectedFlag, endDisconnectedFlag);
+ FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph);
+ String commonLabel = scheme.generateLabel(graph, diagramResource);
+ graph.claimLiteral(startDisconnectedFlag, L0.HasLabel, DIA.FlagLabel, commonLabel);
+ graph.claimLiteral(endDisconnectedFlag, L0.HasLabel, DIA.FlagLabel, commonLabel);
+
+ // Set connection type according to modeling rules
+ setJoinedConnectionTypes(graph, modelingRules, judgment, join);
+
+ // Add comment to change set.
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Connected flags"));
+
+ return;
+ }
+ case 1: {
+ // First connect the flags together
+ Resource join = FlagUtil.join(graph, startDisconnectedFlag, endDisconnectedFlag);
+
+ // Set connection type according to modeling rules
+ setJoinedConnectionTypes(graph, modelingRules, judgment, join);
+
+ // Join the flags into a direct connection
+ new Joiner(graph).joinLocal(graph, Arrays.asList(startDisconnectedFlag, endDisconnectedFlag));
+
+ // Add comment to change set.
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Joined flags"));
+
+ return;
+ }
+ }
+ }
+ }, new Callback<DatabaseException>() {
+ @Override
+ public void run(DatabaseException e) {
+ if (e != null)
+ ErrorLogger.defaultLogError(e);
+ }
+ });
+ }
+ }
+ });
+
+ return;
+ }
+
+ TerminalInfo normalTerminal = null;
+ Resource flagToRemove = null;
+ Resource connection = null;
+ if (startDisconnectedFlag != null) {
+ flagToRemove = startDisconnectedFlag;
+ normalTerminal = endTerminal;
+ connection = attachedToExistingConnection(graph, startTerminal);
+ }
+ if (endDisconnectedFlag != null) {
+ flagToRemove = endDisconnectedFlag;
+ normalTerminal = startTerminal;
+ connection = attachedToExistingConnection(graph, endTerminal);
+ }
+ if (connection != null) {
+ // OK, continuing a connection from an existing disconnected flag.
+
+ // STEPS TO PERFORM:
+ // 1. remove flag
+ // 2. connect normal terminal directly to the existing connection
+ Statement stm = graph.getSingleStatement(flagToRemove, STR.IsConnectedTo);
+ Collection<Resource> areConnecteds = graph.getObjects(stm.getObject(), DIA.AreConnected);
+
+ // Remove statement to connection connector before removing flag
+ // to prevent removal of connector and the connection.
+ graph.deny(stm);
+ new RemoveElement((Resource)diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE), flagToRemove).perform(graph);
+
+ // Disconnect the connector from the connection and create a
+ // new connector for the element terminal.
+ cu.removeConnectionPart(stm.getObject());
+ Connector newConnector = createConnectorForNode(graph, connection,
+ (Resource) ElementUtils.getObject(normalTerminal.e), normalTerminal.t,
+ startDisconnectedFlag != null ? EdgeEnd.End : EdgeEnd.Begin, judgment);
+
+ for (Resource areConnected : areConnecteds)
+ graph.claim(newConnector.getConnector(), DIA.AreConnected, areConnected);
+
+ if (modelingRules != null && judgment.connectionType != null)
+ modelingRules.setConnectionType(graph, connection, judgment.connectionType);
+
+ // Add comment to change set.
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Joined flags"));
+ graph.markUndoPoint();
+ this.cu = null;
+ return;
+ }
+ }
+
+ // 1. Get diagram connection to construct.
+ Resource connection = getOrCreateConnection(graph, startTerminal, endTerminal);
+
+ // 1.1 Give running name to connection and increment the counter attached to the diagram.
+ AddElement.claimFreshElementName(graph, diagramResource, connection);
+
+ // 2. Add branch points
+ // 3. Create edges between branch points.
+ List<Pair<ControlPoint, Resource>> bps = Collections.emptyList();
+ Resource firstBranchPoint = null;
+ Resource lastBranchPoint = null;
+ if (!isRouteGraphConnection(graph, connection)) {
+ bps = createBranchPoints(graph, connection, controlPoints);
+ if (!bps.isEmpty()) {
+ Iterator<Pair<ControlPoint, Resource>> it = bps.iterator();
+ Pair<ControlPoint, Resource> prev = it.next();
+ firstBranchPoint = prev.second;
+ while (it.hasNext()) {
+ Pair<ControlPoint, Resource> next = it.next();
+ cu.connect(prev.second, next.second);
+ prev = next;
+ }
+ lastBranchPoint = prev.second;
+ }
+ }
+
+ // 4. Connect start/end terminals if those exist.
+ // If first/lastBranchPoint != null, connect to those.
+ // Otherwise connect the start/end terminals together.
+ Connector startConnector = null;
+ Connector endConnector = null;
+ IElement startFlag = null;
+ IElement endFlag = null;
+
+ //FlagLabelingScheme scheme = DiagramFlagPreferences.getActiveFlagLabelingScheme(graph);
+
+ if (startTerminal != null && endTerminal != null) {
+ Resource startAttachment = chooseAttachmentRelationForNode(graph, connection, startTerminal, judgment);
+ Resource endAttachment = chooseAttachmentRelationForNode(graph, connection, endTerminal, judgment);
+ Pair<Resource, Resource> attachments = resolveEndAttachments(graph, startAttachment, endAttachment);
+ startConnector = createConnectorForNodeWithAttachment(graph, connection, startTerminal, attachments.first);
+ endConnector = createConnectorForNodeWithAttachment(graph, connection, endTerminal, attachments.second);
+ } else if (startTerminal != null) {
+ startConnector = createConnectorForNode(graph, connection, startTerminal, EdgeEnd.Begin, judgment);
+ if (createFlags) {
+ EdgeEnd flagEnd = cu.toEdgeEnd( cu.getAttachmentRelationForConnector(startConnector.getConnector()), EdgeEnd.End ).other();
+ endFlag = createFlag(graph, connection, flagEnd, controlPoints.getLast(), FlagClass.Type.Out,
+ //scheme.generateLabel(graph, diagramResource));
+ null);
+ endConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(endFlag),
+ ElementUtils.getSingleTerminal(endFlag), flagEnd, judgment);
+ }
+ } else if (endTerminal != null) {
+ endConnector = createConnectorForNode(graph, connection, endTerminal, EdgeEnd.End, judgment);
+ if (createFlags) {
+ EdgeEnd flagEnd = cu.toEdgeEnd( cu.getAttachmentRelationForConnector(endConnector.getConnector()), EdgeEnd.Begin ).other();
+ startFlag = createFlag(graph, connection, flagEnd, controlPoints.getFirst(), FlagClass.Type.In,
+ //scheme.generateLabel(graph, diagramResource));
+ null);
+ startConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(startFlag),
+ ElementUtils.getSingleTerminal(startFlag), flagEnd, judgment);
+ }
+ } else if (createFlags) {
+ startFlag = createFlag(graph, connection, EdgeEnd.Begin, controlPoints.getFirst(), FlagClass.Type.In,
+ //scheme.generateLabel(graph, diagramResource));
+ null);
+ startConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(startFlag),
+ ElementUtils.getSingleTerminal(startFlag), EdgeEnd.Begin, judgment);
+
+ endFlag = createFlag(graph, connection, EdgeEnd.End, controlPoints.getLast(), FlagClass.Type.Out,
+ //scheme.generateLabel(graph, diagramResource));
+ null);
+ endConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(endFlag),
+ ElementUtils.getSingleTerminal(endFlag), EdgeEnd.End, judgment);
+ }
+
+ if (firstBranchPoint == null || lastBranchPoint == null) {
+ cu.connect(startConnector.getConnector(), endConnector.getConnector());
+ } else {
+ cu.connect(startConnector.getConnector(), firstBranchPoint);
+ cu.connect(lastBranchPoint, endConnector.getConnector());
+ }
+
+ // 5. Finally, set connection type according to modeling rules
+ if (judgment.connectionType != null && modelingRules != null)
+ modelingRules.setConnectionType(graph, connection, judgment.connectionType);
+
+ // 5.1 Verify created flag types
+ if (startFlag != null)
+ verifyFlagType(graph, modelingRules, startFlag);
+ if (endFlag != null)
+ verifyFlagType(graph, modelingRules, endFlag);
+
+ // 5.2 Write ConnectionMappingSpecification to connector if necessary
+ writeConnectionMappingSpecification(graph, startTerminal, startConnector, judgment.connectionType);
+ writeConnectionMappingSpecification(graph, endTerminal, endConnector, judgment.connectionType);
+
+ // 6. Add comment to change set.
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Added connection " + connection));
+ graph.markUndoPoint();
+ this.cu = null;
+ }
+
+ private boolean writeConnectionMappingSpecification(WriteGraph graph, TerminalInfo terminal, Connector connector, Resource connectionType)
+ throws DatabaseException {
+ Resource diagramConnRel = getConnectionRelation(graph, terminal);
+ if (diagramConnRel == null)
+ return false;
+ Resource connRel = graph.getPossibleObject(diagramConnRel, MOD.DiagramConnectionRelationToConnectionRelation);
+ if (connRel == null || !graph.hasStatement(connRel, MOD.NeedsConnectionMappingSpecification))
+ return false;
+ Resource mappingSpecification = graph.getPossibleObject(connectionType, MOD.ConnectionTypeToConnectionMappingSpecification);
+ if (mappingSpecification == null)
+ return false;
+ graph.claim(connector.getConnector(), MOD.HasConnectionMappingSpecification, null, mappingSpecification);
+ return true;
+ }
+
+ private static Resource getConnectionRelation(ReadGraph graph, TerminalInfo ti) throws DatabaseException {
+ if (ti != null && ti.t instanceof ResourceTerminal) {
+ Resource t = ((ResourceTerminal) ti.t).getResource();
+ Resource bindingRelation = DiagramGraphUtil.getConnectionPointOfTerminal(graph, t);
+ return bindingRelation;
+ }
+ return null;
+ }
+
+ /**
+ * @param graph
+ * @param startAttachment
+ * @param endAttachment
+ * @return
+ * @throws DatabaseException
+ */
+ protected Pair<Resource, Resource> resolveEndAttachments(WriteGraph graph,
+ Resource startAttachment, Resource endAttachment) throws DatabaseException {
+ if (startAttachment != null && endAttachment != null)
+ return Pair.make(startAttachment, endAttachment);
+
+ if (startAttachment != null && endAttachment == null)
+ return Pair.make(startAttachment, getInverseAttachment(graph, startAttachment, DIA.HasArrowConnector));
+ if (startAttachment == null && endAttachment != null)
+ return Pair.make(getInverseAttachment(graph, endAttachment, DIA.HasPlainConnector), endAttachment);
+
+ return Pair.make(DIA.HasPlainConnector, DIA.HasArrowConnector);
+ }
+
+ /**
+ * @param graph
+ * @param attachment
+ * @return
+ * @throws DatabaseException
+ */
+ protected Resource getInverseAttachment(ReadGraph graph, Resource attachment, Resource defaultValue) throws DatabaseException {
+ Resource inverse = attachment != null ? graph.getPossibleObject(attachment, DIA.HasInverseAttachment) : defaultValue;
+ return inverse != null ? inverse : defaultValue;
+ }
+
+ /**
+ * @param graph
+ * @param modelingRules
+ * @param flagElement
+ * @throws DatabaseException
+ */
+ protected void verifyFlagType(WriteGraph graph, IModelingRules modelingRules, IElement flagElement) throws DatabaseException {
+ if (modelingRules != null) {
+ Resource flag = flagElement.getHint(ElementHints.KEY_OBJECT);
+ FlagClass.Type flagType = flagElement.getHint(FlagClass.KEY_FLAG_TYPE);
+ FlagUtil.verifyFlagType(graph, modelingRules, flag, flagType);
+ }
+ }
+
+ /**
+ * @param graph
+ * @param judgment
+ * @param connection
+ * @param attachToLine
+ * @param controlPoints
+ * @param endTerminal
+ * @return the DIA.Connector instance created for attaching the connection
+ * to the specified end terminal
+ * @throws DatabaseException
+ */
+ public Pair<Resource, Resource> attachToRouteGraph(
+ WriteGraph graph,
+ ConnectionJudgement judgment,
+ Resource attachToConnection,
+ Resource attachToLine,
+ Deque<ControlPoint> controlPoints,
+ TerminalInfo endTerminal,
+ FlagClass.Type flagType)
+ throws DatabaseException
+ {
+ initializeResources(graph);
+ this.cu = new ConnectionUtil(graph);
+ try {
+ Resource endElement = endTerminal != null ? ElementUtils.getObject(endTerminal.e) : null;
+ if (endElement != null
+ && graph.isInstanceOf(endElement, DIA.Flag)
+ && FlagUtil.isDisconnected(graph, endElement))
+ {
+ // Connection ends in an existing but disconnected flag that
+ // should be all right to connect to because the connection
+ // judgment implies it makes a valid connection.
+ // Check that we are attaching the connection to an existing
+ // disconnected flag that is however attached to a connection.
+ Resource endTerminalConnection = ConnectionBuilder.attachedToExistingConnection(graph, endTerminal);
+ if (endTerminalConnection != null) {
+ attachConnectionToFlag(graph, judgment, attachToConnection, attachToLine, controlPoints, endTerminal);
+ return null;
+ }
+ }
+
+ Connector endConnector = null;
+ if (endTerminal != null) {
+ endConnector = createConnectorForNode(graph, attachToConnection, endTerminal, EdgeEnd.End, judgment);
+ } else if (createFlags) {
+ EdgeEnd end = flagType == FlagClass.Type.In ? EdgeEnd.Begin : EdgeEnd.End;
+ IElement endFlag = createFlag(graph, attachToConnection, end, controlPoints.getLast(), flagType, null);
+ endConnector = createConnectorForNode(graph, attachToConnection, (Resource) ElementUtils.getObject(endFlag),
+ ElementUtils.getSingleTerminal(endFlag), end, judgment);
+ }
+
+ cu.connect(attachToLine, endConnector.getConnector());
+
+ IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);
+ if (judgment.connectionType != null && modelingRules != null) {
+ modelingRules.setConnectionType(graph, attachToConnection, judgment.connectionType);
+ }
+
+ writeConnectionMappingSpecification(graph, endTerminal, endConnector, judgment.connectionType);
+
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Branched connection " + attachToConnection));
+
+ return Pair.make(endConnector.getAttachment(), endConnector.getConnector());
+ } finally {
+ this.cu = null;
+ }
+ }
+
+ protected void attachConnectionToFlag(
+ WriteGraph graph,
+ ConnectionJudgement judgment,
+ Resource attachToConnection,
+ Resource attachToLine,
+ Deque<ControlPoint> controlPoints,
+ TerminalInfo toFlag)
+ throws DatabaseException
+ {
+ // Attaching attachedConnection to an existing disconnected flag that is
+ // however attached to a connection.
+ // STEPS:
+ // 1. remove flag and its connector
+ // 2. attach the two connections together by moving the route nodes
+ // of the removed flag-side connection under the remaining connection
+ // and ensuring that the route node chain will be valid after the
+ // switch. In a chain route lines, each line must have an opposite
+ // direction compared to the lines connected to it.
+ Resource flagToRemove = ElementUtils.getObject(toFlag.e);
+ Statement flagToConnector = graph.getSingleStatement(flagToRemove, STR.IsConnectedTo);
+ Resource flagConnector = flagToConnector.getObject();
+ Resource flagConnection = ConnectionUtil.getConnection(graph, flagConnector);
+ Collection<Resource> flagRouteNodes = graph.getObjects(flagConnector, DIA.AreConnected);
+
+ Resource connectionToKeep = attachToConnection;
+ Resource connectionToRemove = flagConnection;
+ if (!connectionToKeep.equals(connectionToRemove)) {
+ Resource hasElementToComponent1 = graph.getPossibleObject(attachToConnection, MOD.ElementToComponent);
+ Resource hasElementToComponent2 = graph.getPossibleObject(flagConnection, MOD.ElementToComponent);
+ Type flagType = FlagUtil.getFlagType(graph, flagToRemove);
+ if (hasElementToComponent1 != null && hasElementToComponent2 != null)
+ throw new UnsupportedOperationException(
+ "Both attached connection " + attachToConnection + " and flag connection " + flagConnection
+ + " have mapped components, can't decide which connection to remove in join operation");
+ if (hasElementToComponent2 != null || flagType == Type.Out) {
+ connectionToKeep = flagConnection;
+ connectionToRemove = attachToConnection;
+ }
+ }
+
+ // Remove flag and its connector.
+ graph.deny(flagToConnector);
+ new RemoveElement((Resource)diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE), flagToRemove).perform(graph);
+ cu.removeConnectionPart(flagConnector);
+
+ // Attached routeline must have opposite direction than the line
+ // attached to in order for the connection to be valid.
+ Boolean attachingToHorizontalLine = graph.getPossibleRelatedValue(attachToLine, DIA.IsHorizontal, Bindings.BOOLEAN);
+ if (attachingToHorizontalLine != null) {
+ for (Resource routeNode : flagRouteNodes) {
+ Collection<Resource> routeNodesToAttachTo = removeUntilOrientedRouteline(graph, !attachingToHorizontalLine, routeNode);
+ for (Resource rn : routeNodesToAttachTo)
+ cu.connect(attachToLine, rn);
+ }
+ }
+
+ moveStatements(graph, connectionToRemove, connectionToKeep, DIA.HasInteriorRouteNode);
+ moveStatements(graph, connectionToRemove, connectionToKeep, DIA.HasConnector);
+
+ // Remove obsolete connection
+ if (!connectionToKeep.equals(connectionToRemove))
+ cu.removeConnection(connectionToRemove);
+
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Joined connection to disconnected flag"));
+ }
+
+ private void moveStatements(WriteGraph graph, Resource source, Resource target, Resource movedRelation) throws DatabaseException {
+ if (!source.equals(target)) {
+ for (Statement s : graph.getStatements(source, movedRelation)) {
+ graph.deny(s);
+ graph.claim(target, s.getPredicate(), s.getObject());
+ }
+ }
+ }
+
+ private Collection<Resource> removeUntilOrientedRouteline(WriteGraph graph, boolean expectedOrientation, Resource routeNode) throws DatabaseException {
+ List<Resource> result = new ArrayList<>(2);
+ Deque<Resource> work = new ArrayDeque<>(2);
+ work.addLast(routeNode);
+ while (!work.isEmpty()) {
+ Resource rn = work.removeFirst();
+ if (graph.isInstanceOf(rn, DIA.RouteLine)) {
+ Boolean isHorizontal = graph.getPossibleRelatedValue(rn, DIA.IsHorizontal, Bindings.BOOLEAN);
+ if (isHorizontal != null && expectedOrientation != isHorizontal) {
+ for (Resource rnn : graph.getObjects(rn, DIA.AreConnected))
+ work.addLast(rnn);
+ cu.removeConnectionPart(rn);
+ continue;
+ }
+ }
+ result.add(rn);
+ }
+ return result;
+ }
+
+ protected boolean isRouteGraphConnection(ReadGraph graph, Resource connection) throws DatabaseException {
+ initializeResources(graph);
+ return graph.isInstanceOf(connection, DIA.RouteGraphConnection);
+ }
+
+ /**
+ * @param graph
+ * @param ti
+ * @return
+ * @throws DatabaseException
+ */
+ public static Resource attachedToExistingConnection(ReadGraph graph, TerminalInfo ti) throws DatabaseException {
+ Object obj = ElementUtils.getObject(ti.e);
+ Resource cp = DiagramGraphUtil.getConnectionPointOfTerminal(graph, ti.t);
+ if (obj instanceof Resource && cp != null) {
+ Resource e = (Resource) obj;
+ for (Resource connector : graph.getObjects(e, cp)) {
+ Resource connection = ConnectionUtil.tryGetConnection(graph, connector);
+ if (connection != null)
+ return connection;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param graph
+ * @param tis
+ * @return
+ * @throws DatabaseException
+ */
+ public Resource getOrCreateConnection(ReadGraph graph, TerminalInfo... tis) throws DatabaseException {
+ // Resolve if adding to existing connection.
+ Resource connection = null;
+ for (TerminalInfo ti : tis) {
+ connection = getExistingConnection(graph, ti);
+ if (connection != null)
+ break;
+ }
+
+ if (connection == null) {
+ // No existing connection, create new.
+ ElementClass connectionClass = elementClassProvider.get(ElementClasses.CONNECTION);
+ Resource connectionClassResource = ElementUtils.checkedAdapt(connectionClass, Resource.class);
+ connection = cu.newConnection(diagramResource, connectionClassResource);
+ }
+
+ return connection;
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param controlPoints
+ * @return
+ * @throws DatabaseException
+ */
+ public List<Pair<ControlPoint, Resource>> createBranchPoints(WriteGraph graph, Resource connection,
+ Collection<ControlPoint> controlPoints) throws DatabaseException {
+ List<Pair<ControlPoint, Resource>> bps = new ArrayList<Pair<ControlPoint, Resource>>(controlPoints.size());
+ for(ControlPoint cp : controlPoints) {
+ if (cp.isAttachedToTerminal())
+ // Terminal attachments do not need branch points.
+ continue;
+
+ Resource bp = cu.newBranchPoint(connection,
+ AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY()),
+ cp.getDirection());
+ bps.add(Pair.make(cp, bp));
+ }
+ return bps;
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param ti
+ * @param end
+ * @param judgment
+ * @return
+ * @throws DatabaseException
+ */
+ protected Resource chooseAttachmentRelationForNode(ReadGraph graph,
+ Resource connection, TerminalInfo ti, ConnectionJudgement judgment)
+ throws DatabaseException {
+ Resource node = (Resource) ElementUtils.getObject(ti.e);
+ return chooseAttachmentRelationForNode(graph, connection, node, ti.t, judgment);
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param element
+ * @param terminal
+ * @param end
+ * @param judgment
+ * @return the calculated attachment relation or <code>null</code> if the
+ * result is ambiguous
+ * @throws DatabaseException
+ */
+ protected Resource chooseAttachmentRelationForNode(ReadGraph graph,
+ Resource connection, Resource element, Terminal terminal,
+ ConnectionJudgement judgment) throws DatabaseException {
+ IConnectionPoint cp = ConnectionUtil.toConnectionPoint(graph, element, terminal);
+ CPTerminal cpt = (cp instanceof CPTerminal) ? (CPTerminal) cp : null;
+ Resource attachment = judgment.attachmentRelations.get(graph, cpt);
+ return attachment;
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param ti
+ * @param connectTo resource to connect the new connector to if not
+ * <code>null</code>
+ * @param judgment
+ * @return <used attachment relation, the new DIA.Connector instance>. The
+ * attachment relation is <code>null</code> if it was chosen based
+ * on EdgeEnd instead of being defined
+ * @throws DatabaseException
+ */
+ protected Connector createConnectorForNode(WriteGraph graph, Resource connection, TerminalInfo ti, EdgeEnd end,
+ ConnectionJudgement judgment) throws DatabaseException {
+ Resource node = (Resource) ElementUtils.getObject(ti.e);
+ return createConnectorForNode(graph, connection, node, ti.t, end, judgment);
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param element
+ * @param terminal
+ * @param end
+ * @param connectTo
+ * @param judgment
+ * @return <used attachment relation, the new DIA.Connector instance>. The
+ * attachment relation is <code>null</code> if it was chosen based
+ * on EdgeEnd instead of being defined
+ * @throws DatabaseException
+ */
+ protected Connector createConnectorForNode(WriteGraph graph, Resource connection, Resource element, Terminal terminal,
+ EdgeEnd end, ConnectionJudgement judgment) throws DatabaseException {
+ IConnectionPoint cp = ConnectionUtil.toConnectionPoint(graph, element, terminal);
+ CPTerminal cpt = (cp instanceof CPTerminal) ? (CPTerminal) cp : null;
+ Resource attachment = judgment.attachmentRelations.get(graph, cpt);
+ if (attachment == null)
+ attachment = cu.toHasConnectorRelation(end);
+ Resource connector = cu.getOrCreateConnector(connection, element, terminal, end, attachment);
+ return new Connector(attachment, connector);
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param ti
+ * @param attachment
+ * @return <used attachment relation, the new DIA.Connector instance>
+ * @throws DatabaseException
+ */
+ protected Connector createConnectorForNodeWithAttachment(WriteGraph graph,
+ Resource connection, TerminalInfo ti, Resource attachment)
+ throws DatabaseException {
+ Resource node = (Resource) ElementUtils.getObject(ti.e);
+ return createConnectorForNodeWithAttachment(graph, connection, node, ti.t, attachment);
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param element
+ * @param terminal
+ * @param attachment
+ * @return <used attachment relation, the new DIA.Connector instance>
+ * @throws DatabaseException
+ */
+ protected Connector createConnectorForNodeWithAttachment(WriteGraph graph,
+ Resource connection, Resource element, Terminal terminal,
+ Resource attachment) throws DatabaseException {
+ Resource connector = cu.getOrCreateConnector(connection, element, terminal, null, attachment);
+ return new Connector(attachment, connector);
+ }
+
+ /**
+ * @param graph
+ * @param connection
+ * @param end
+ * @param cp
+ * @param type
+ * @param label <code>null</code> to leave flag without label
+ * @return an element describing the new created flag resource
+ * @throws DatabaseException
+ */
+ public IElement createFlag(WriteGraph graph, Resource connection, EdgeEnd end, ControlPoint cp,
+ FlagClass.Type type, String label) throws DatabaseException {
+ ElementClass flagClass = elementClassProvider.get(ElementClasses.FLAG);
+ IElement flagElement = Element.spawnNew(flagClass);
+ Resource flagClassResource = ElementUtils.checkedAdapt(flagClass, Resource.class);
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ G2DResource G2D = G2DResource.getInstance(graph);
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+
+ Resource flag = graph.newResource();
+ graph.claim(flag, L0.InstanceOf, null, flagClassResource);
+ flagElement.setHint(ElementHints.KEY_OBJECT, flag);
+
+ OrderedSetUtils.add(graph, diagramResource, flag);
+
+ AffineTransform at = AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY());
+ flagElement.setHint(ElementHints.KEY_TRANSFORM, at);
+ double[] matrix = new double[6];
+ at.getMatrix(matrix);
+ graph.claimLiteral(flag, DIA.HasTransform, G2D.Transform, matrix);
+
+ flagElement.setHint(FlagClass.KEY_FLAG_TYPE, type);
+ graph.claim(flag, DIA.HasFlagType, null, DiagramGraphUtil.toFlagTypeResource(DIA, type));
+ if (label != null)
+ graph.claimLiteral(flag, L0.HasLabel, DIA.FlagLabel, label, Bindings.STRING);
+
+ // Give running name to flag and increment the counter attached to the diagram.
+ AddElement.claimFreshElementName(graph, diagramResource, flag);
+
+ // Make the diagram consist of the new element
+ graph.claim(diagramResource, L0.ConsistsOf, flag);
+
+ // Put the element on all the currently active layers if possible.
+ if (layerManager != null) {
+ layerManager.removeFromAllLayers(graph, flag);
+ layerManager.putElementOnVisibleLayers(diagram, graph, flag);
+ }
+
+ // Add flag to possible IO table
+ IOTablesInfo ioTablesInfo = IOTableUtil.getIOTablesInfo(graph,
+ (Resource)diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE));
+ ioTablesInfo.updateBinding(graph, DIA, flag, at.getTranslateX(), at.getTranslateY());
+
+ return flagElement;
+ }
+
+ /**
+ * @param graph
+ * @param ti
+ * @return
+ * @throws DatabaseException
+ */
+ protected static Resource getExistingConnection(ReadGraph graph, TerminalInfo ti) throws DatabaseException {
+ if (ti != null) {
+ if (isConnection(ti.e)) {
+ Object obj = ElementUtils.getObject(ti.e);
+ if (obj instanceof Resource) {
+ Resource c = (Resource) obj;
+ return graph.isInstanceOf(c, DiagramResource.getInstance(graph).Connection) ? c : null;
+ }
+ } else if (isBranchPoint(ti.e)) {
+ Object obj = ElementUtils.getObject(ti.e);
+ if (obj instanceof Resource) {
+ return ConnectionUtil.tryGetConnection(graph, (Resource) obj);
+ }
+ }
+ }
+ return null;
+ }
+
+ protected static boolean isConnection(IElement e) {
+ return e.getElementClass().containsClass(ConnectionHandler.class);
+ }
+
+ /**
+ * @param e
+ * @return
+ */
+ protected static boolean isBranchPoint(IElement e) {
+ return e.getElementClass().containsClass(BranchPoint.class);
+ }
+
+ /**
+ * @param graph
+ * @param terminal
+ * @return
+ * @throws DatabaseException
+ */
+ protected static Resource getDisconnectedFlag(ReadGraph graph, TerminalInfo terminal) throws DatabaseException {
+ if (terminal != null) {
+ Object obj = ElementUtils.getObject(terminal.e);
+ if (obj instanceof Resource) {
+ Resource flag = (Resource) obj;
+ if (graph.isInstanceOf(flag, DiagramResource.getInstance(graph).Flag)
+ && FlagUtil.isDisconnected(graph, flag))
+ return flag;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param graph
+ * @param modelingRules
+ * @param judgment
+ * @param join
+ * @throws DatabaseException
+ */
+ protected static void setJoinedConnectionTypes(WriteGraph graph, IModelingRules modelingRules,
+ ConnectionJudgement judgment, Resource join) throws DatabaseException {
+ if (modelingRules != null && judgment != null && judgment.connectionType != null) {
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ List<Resource> connections = new ArrayList<Resource>(2);
+ for (Resource flag : graph.getObjects(join, DIA.FlagIsJoinedBy)) {
+ for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
+ Resource connection = ConnectionUtil.tryGetConnection(graph, connector);
+ if (connection != null)
+ connections.add(connection);
+ }
+ }
+ for (Resource connection : connections)
+ modelingRules.setConnectionType(graph, connection, judgment.connectionType);
+ }
+ }
+
}
\ No newline at end of file