--- /dev/null
+/*******************************************************************************\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