]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / handler / ConnectionSplitAndJoin.java
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java
new file mode 100644 (file)
index 0000000..9e7a163
--- /dev/null
@@ -0,0 +1,304 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 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
+ *******************************************************************************/\r
+package org.simantics.diagram.handler;\r
+\r
+import java.awt.geom.Point2D;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.ActionContributionItem;\r
+import org.eclipse.jface.action.IContributionItem;\r
+import org.eclipse.swt.widgets.Menu;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.IndexRoot;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.content.EdgeResource;\r
+import org.simantics.diagram.flag.FlagUtil;\r
+import org.simantics.diagram.flag.Splitter;\r
+import org.simantics.diagram.internal.Activator;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.participant.Selection;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.scl.commands.Command;\r
+import org.simantics.scl.commands.Commands;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.ui.contribution.DynamicMenuContribution;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+import org.simantics.utils.ui.AdaptionUtils;\r
+import org.simantics.utils.ui.ExceptionUtils;\r
+import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class ConnectionSplitAndJoin extends DynamicMenuContribution {\r
+\r
+    private static final IContributionItem[] NONE = {};\r
+\r
+    private ICanvasContext canvas;\r
+\r
+    @Override\r
+    public void fill(Menu menu, int index) {\r
+        // Need to grab active part here, we're still in the SWT thread.\r
+        IWorkbenchPart activePart = WorkbenchUtils.getActiveWorkbenchPart();\r
+        if (activePart == null)\r
+            return;\r
+        ICanvasContext ctx = (ICanvasContext) activePart.getAdapter(ICanvasContext.class);\r
+        if (ctx == null)\r
+            return;\r
+\r
+        this.canvas = ctx;\r
+        try {\r
+            super.fill(menu, index);\r
+        } finally {\r
+            this.canvas = null;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException {\r
+        // If selection contains:\r
+        // a) only diagram-locally connected flags, that each are connected to something, allow joining of those flag into connections\r
+        // b) a single connection edge element, allow splitting into a connected flag pair\r
+\r
+        Collection<Resource> localConnectedFlags = Collections.emptyList();\r
+        Resource routeGraphConnection = null;\r
+        EdgeResource edge = null;\r
+        if (selection.length == 1) {\r
+            routeGraphConnection = getRouteGraphConnection(graph, selection[0]);\r
+            if (routeGraphConnection == null) {\r
+                edge = getEdge(graph, selection[0]);\r
+                if (edge == null)\r
+                    localConnectedFlags = getLocalConnectedFlags(graph, selection);\r
+            }\r
+        } else {\r
+            localConnectedFlags = getLocalConnectedFlags(graph, selection);\r
+        }\r
+\r
+        if (!localConnectedFlags.isEmpty()) {\r
+            return new IContributionItem[] {\r
+                    new ActionContributionItem(new Join(graph.getSession(), canvas, localConnectedFlags))\r
+            };\r
+        } else if (edge != null) {\r
+            Selection sel = canvas.getAtMostOneItemOfClass(Selection.class);\r
+            if (sel == null)\r
+                return NONE;\r
+            Set<IElement> elems = sel.getSelection(0);\r
+            if (elems.size() != 1)\r
+                return NONE;\r
+            IElement edgeElement = ConnectionUtil.getSingleEdge(elems.iterator().next());\r
+            if (edgeElement == null)\r
+                return NONE;\r
+            Point2D canvasPosition = canvas.getHintStack().getHint(DiagramHints.POPUP_MENU_CANVAS_POSITION);\r
+            if (canvasPosition == null)\r
+                return NONE;\r
+\r
+            return new IContributionItem[] {\r
+                    new ActionContributionItem(new Split(graph.getSession(), canvas, canvasPosition, edgeElement, edge))\r
+            };\r
+        } else if (routeGraphConnection != null) {\r
+            Selection sel = canvas.getAtMostOneItemOfClass(Selection.class);\r
+            if (sel == null)\r
+                return NONE;\r
+            Set<IElement> elems = sel.getSelection(0);\r
+            if (elems.size() != 1)\r
+                return NONE;\r
+            Point2D canvasPosition = canvas.getHintStack().getHint(DiagramHints.POPUP_MENU_CANVAS_POSITION);\r
+            if (canvasPosition == null)\r
+                return NONE;\r
+\r
+            return new IContributionItem[] {\r
+                    new ActionContributionItem(new SplitRouteGraph(graph.getSession(), canvas, canvasPosition, routeGraphConnection))\r
+            };\r
+        }\r
+        return NONE;\r
+    }\r
+\r
+    private Resource getRouteGraphConnection(ReadGraph graph, Object object) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        Resource connection = AdaptionUtils.adaptToSingle(object, Resource.class);\r
+        if (connection != null && graph.isInstanceOf(connection, DIA.RouteGraphConnection))\r
+            return connection;\r
+        return null;\r
+    }\r
+\r
+    private Collection<Resource> getLocalConnectedFlags(ReadGraph graph, Object[] selection) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        ArrayList<Resource> result = new ArrayList<Resource>(4);\r
+        for (Object s : selection) {\r
+            Resource r = AdaptionUtils.adaptToSingle(s, Resource.class);\r
+            if (r == null || !graph.isInstanceOf(r, DIA.Flag))\r
+                return Collections.emptyList();\r
+            Resource counterpart = FlagUtil.getPossibleCounterpart(graph, r);\r
+            if (counterpart == null)\r
+                return Collections.emptyList();\r
+            if (!FlagUtil.isJoinedInSingleDiagram(graph, r))\r
+                return Collections.emptyList();\r
+            if (!isConnectedToSomething(graph, r) || !isConnectedToSomething(graph, counterpart))\r
+                return Collections.emptyList();\r
+            result.add(r);\r
+        }\r
+        return result;\r
+    }\r
+\r
+    private boolean isConnectedToSomething(ReadGraph graph, Resource flag) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+        for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {\r
+            Resource cntr = graph.getPossibleObject(connector, DIA.AreConnected);\r
+            Resource conn = ConnectionUtil.getConnection(graph, cntr);\r
+            if (cntr == null || conn == null)\r
+                return false;\r
+            return true;\r
+        }\r
+        return false;\r
+    }\r
+\r
+    private EdgeResource getEdge(ReadGraph graph, Object object) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+\r
+        Resource connection = null;\r
+        EdgeResource edge = AdaptionUtils.adaptToSingle(object, EdgeResource.class);\r
+        if (edge != null)\r
+            //connection = ConnectionUtil.getConnection(graph, edge);\r
+            return edge;\r
+        else {\r
+            connection = AdaptionUtils.adaptToSingle(object, Resource.class);\r
+        }\r
+\r
+        if (connection != null && graph.isInstanceOf(connection, DiagramResource.getInstance(graph).Connection)) {\r
+            Collection<Resource> connectors = graph.getObjects(connection, DIA.HasConnector);\r
+            Collection<Resource> branchPoints = graph.getObjects(connection, DIA.HasBranchPoint);\r
+            if (branchPoints.isEmpty() && connectors.size() == 2) {\r
+                Iterator<Resource> it = connectors.iterator();\r
+                Resource connector1 = it.next();\r
+                Resource connector2 = it.next();\r
+                return new EdgeResource(connector1, connector2);\r
+            }\r
+        }\r
+\r
+        return null;\r
+    }\r
+\r
+    public static abstract class Helper extends Action {\r
+\r
+        protected final Session        session;\r
+        protected final ICanvasContext context;\r
+\r
+        public Helper(String label, Session session, ICanvasContext context) {\r
+            super(label);\r
+            this.session = session;\r
+            this.context = context;\r
+        }\r
+\r
+        @Override\r
+        public void run() {\r
+            try {\r
+                session.syncRequest(new WriteRequest() {\r
+                    @Override\r
+                    public void perform(WriteGraph graph) throws DatabaseException {\r
+                        graph.markUndoPoint();\r
+                        performAction(graph);\r
+                    }\r
+                });\r
+                ThreadUtils.asyncExec(context.getThreadAccess(), new Runnable() {\r
+                    @Override\r
+                    public void run() {\r
+                        if (context.isDisposed())\r
+                            return;\r
+                        Selection selection = context.getAtMostOneItemOfClass(Selection.class);\r
+                        if (selection != null) {\r
+                            // This prevents workbench selection from being left over.\r
+                            // Also prevents scene graph crap from being left on the screen.\r
+                            selection.clear(0);\r
+                        }\r
+                    }\r
+                });\r
+            } catch (DatabaseException e) {\r
+                ExceptionUtils.logError(e);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * @param graph\r
+         */\r
+        protected abstract void performAction(WriteGraph graph) throws DatabaseException;\r
+\r
+    }\r
+\r
+    public static class Split extends Helper {\r
+        private final Point2D      splitCanvasPos;\r
+        private final IElement     edgeElement;\r
+        private final EdgeResource edge;\r
+\r
+        public Split(Session session, ICanvasContext context, Point2D splitCanvasPos, IElement edgeElement, EdgeResource edge) {\r
+            super("Split Connection", session, context);\r
+            setImageDescriptor(Activator.LINK_BREAK_ICON);\r
+            this.splitCanvasPos = splitCanvasPos;\r
+            this.edgeElement = edgeElement;\r
+            this.edge = edge;\r
+        }\r
+\r
+        @Override\r
+        protected void performAction(WriteGraph graph) throws DatabaseException {\r
+            new Splitter(graph).split(graph, edgeElement, edge, splitCanvasPos);\r
+        }\r
+    }\r
+\r
+    public static class SplitRouteGraph extends Helper {\r
+        private final Point2D  splitCanvasPos;\r
+        private final Resource connection;\r
+\r
+        public SplitRouteGraph(Session session, ICanvasContext context, Point2D splitCanvasPos, Resource connection) {\r
+            super("Split Connection", session, context);\r
+            setImageDescriptor(Activator.LINK_BREAK_ICON);\r
+            this.splitCanvasPos = splitCanvasPos;\r
+            this.connection = connection;\r
+        }\r
+\r
+        @Override\r
+        protected void performAction(WriteGraph graph) throws DatabaseException {\r
+            Command command = Commands.get(graph, "Simantics/Diagram/splitConnection");\r
+            command.execute(graph, graph.syncRequest(new IndexRoot(connection)),\r
+                    connection, splitCanvasPos.getX(), splitCanvasPos.getY());\r
+        }\r
+    }\r
+\r
+    public static class Join extends Helper {\r
+        private final Collection<Resource> flags;\r
+\r
+        public Join(Session session, ICanvasContext context, Collection<Resource> flags) {\r
+            super("Join Flags", session, context);\r
+            setImageDescriptor(Activator.LINK_ICON);\r
+            this.flags = flags;\r
+        }\r
+\r
+        @Override\r
+        protected void performAction(WriteGraph graph) throws DatabaseException {\r
+            Command command = Commands.get(graph, "Simantics/Diagram/joinFlagsLocal");\r
+            command.execute(graph, graph.syncRequest(new IndexRoot(flags.iterator().next())), flags);\r
+        }\r
+    }\r
+\r
+}
\ No newline at end of file