]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionBuilder.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / participant / ConnectionBuilder.java
index b36961f87a589595d939d3045c0482bd3e71939c..72cdb17524fa3def3ae8acc771836153590ffcfe 100644 (file)
-/*******************************************************************************\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
-            FlagClass.Type flagType)\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
-                EdgeEnd end = flagType == FlagClass.Type.In ? EdgeEnd.Begin : EdgeEnd.End;\r
-                IElement endFlag = createFlag(graph, attachToConnection, end, controlPoints.getLast(), flagType, null);\r
-                endConnector = createConnectorForNode(graph, attachToConnection, (Resource) ElementUtils.getObject(endFlag),\r
-                        ElementUtils.getSingleTerminal(endFlag), 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