1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.diagram.handler;
\r
14 import java.awt.geom.Point2D;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Collection;
\r
17 import java.util.Collections;
\r
18 import java.util.Iterator;
\r
19 import java.util.Set;
\r
21 import org.eclipse.jface.action.Action;
\r
22 import org.eclipse.jface.action.ActionContributionItem;
\r
23 import org.eclipse.jface.action.IContributionItem;
\r
24 import org.eclipse.swt.widgets.Menu;
\r
25 import org.eclipse.ui.IWorkbenchPart;
\r
26 import org.simantics.db.ReadGraph;
\r
27 import org.simantics.db.Resource;
\r
28 import org.simantics.db.Session;
\r
29 import org.simantics.db.WriteGraph;
\r
30 import org.simantics.db.common.request.IndexRoot;
\r
31 import org.simantics.db.common.request.WriteRequest;
\r
32 import org.simantics.db.exception.DatabaseException;
\r
33 import org.simantics.diagram.content.ConnectionUtil;
\r
34 import org.simantics.diagram.content.EdgeResource;
\r
35 import org.simantics.diagram.flag.FlagUtil;
\r
36 import org.simantics.diagram.flag.Splitter;
\r
37 import org.simantics.diagram.internal.Activator;
\r
38 import org.simantics.diagram.stubs.DiagramResource;
\r
39 import org.simantics.g2d.canvas.ICanvasContext;
\r
40 import org.simantics.g2d.diagram.DiagramHints;
\r
41 import org.simantics.g2d.diagram.participant.Selection;
\r
42 import org.simantics.g2d.element.IElement;
\r
43 import org.simantics.scl.commands.Command;
\r
44 import org.simantics.scl.commands.Commands;
\r
45 import org.simantics.structural.stubs.StructuralResource2;
\r
46 import org.simantics.ui.contribution.DynamicMenuContribution;
\r
47 import org.simantics.utils.threads.ThreadUtils;
\r
48 import org.simantics.utils.ui.AdaptionUtils;
\r
49 import org.simantics.utils.ui.ExceptionUtils;
\r
50 import org.simantics.utils.ui.workbench.WorkbenchUtils;
\r
53 * @author Tuukka Lehtonen
\r
55 public class ConnectionSplitAndJoin extends DynamicMenuContribution {
\r
57 private static final IContributionItem[] NONE = {};
\r
59 private ICanvasContext canvas;
\r
62 public void fill(Menu menu, int index) {
\r
63 // Need to grab active part here, we're still in the SWT thread.
\r
64 IWorkbenchPart activePart = WorkbenchUtils.getActiveWorkbenchPart();
\r
65 if (activePart == null)
\r
67 ICanvasContext ctx = (ICanvasContext) activePart.getAdapter(ICanvasContext.class);
\r
73 super.fill(menu, index);
\r
80 protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException {
\r
81 // If selection contains:
\r
82 // a) only diagram-locally connected flags, that each are connected to something, allow joining of those flag into connections
\r
83 // b) a single connection edge element, allow splitting into a connected flag pair
\r
85 Collection<Resource> localConnectedFlags = Collections.emptyList();
\r
86 Resource routeGraphConnection = null;
\r
87 EdgeResource edge = null;
\r
88 if (selection.length == 1) {
\r
89 routeGraphConnection = getRouteGraphConnection(graph, selection[0]);
\r
90 if (routeGraphConnection == null) {
\r
91 edge = getEdge(graph, selection[0]);
\r
93 localConnectedFlags = getLocalConnectedFlags(graph, selection);
\r
96 localConnectedFlags = getLocalConnectedFlags(graph, selection);
\r
99 if (!localConnectedFlags.isEmpty()) {
\r
100 return new IContributionItem[] {
\r
101 new ActionContributionItem(new Join(graph.getSession(), canvas, localConnectedFlags))
\r
103 } else if (edge != null) {
\r
104 Selection sel = canvas.getAtMostOneItemOfClass(Selection.class);
\r
107 Set<IElement> elems = sel.getSelection(0);
\r
108 if (elems.size() != 1)
\r
110 IElement edgeElement = ConnectionUtil.getSingleEdge(elems.iterator().next());
\r
111 if (edgeElement == null)
\r
113 Point2D canvasPosition = canvas.getHintStack().getHint(DiagramHints.POPUP_MENU_CANVAS_POSITION);
\r
114 if (canvasPosition == null)
\r
117 return new IContributionItem[] {
\r
118 new ActionContributionItem(new Split(graph.getSession(), canvas, canvasPosition, edgeElement, edge))
\r
120 } else if (routeGraphConnection != null) {
\r
121 Selection sel = canvas.getAtMostOneItemOfClass(Selection.class);
\r
124 Set<IElement> elems = sel.getSelection(0);
\r
125 if (elems.size() != 1)
\r
127 Point2D canvasPosition = canvas.getHintStack().getHint(DiagramHints.POPUP_MENU_CANVAS_POSITION);
\r
128 if (canvasPosition == null)
\r
131 return new IContributionItem[] {
\r
132 new ActionContributionItem(new SplitRouteGraph(graph.getSession(), canvas, canvasPosition, routeGraphConnection))
\r
138 private Resource getRouteGraphConnection(ReadGraph graph, Object object) throws DatabaseException {
\r
139 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
140 Resource connection = AdaptionUtils.adaptToSingle(object, Resource.class);
\r
141 if (connection != null && graph.isInstanceOf(connection, DIA.RouteGraphConnection))
\r
146 private Collection<Resource> getLocalConnectedFlags(ReadGraph graph, Object[] selection) throws DatabaseException {
\r
147 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
148 ArrayList<Resource> result = new ArrayList<Resource>(4);
\r
149 for (Object s : selection) {
\r
150 Resource r = AdaptionUtils.adaptToSingle(s, Resource.class);
\r
151 if (r == null || !graph.isInstanceOf(r, DIA.Flag))
\r
152 return Collections.emptyList();
\r
153 Resource counterpart = FlagUtil.getPossibleCounterpart(graph, r);
\r
154 if (counterpart == null)
\r
155 return Collections.emptyList();
\r
156 if (!FlagUtil.isJoinedInSingleDiagram(graph, r))
\r
157 return Collections.emptyList();
\r
158 if (!isConnectedToSomething(graph, r) || !isConnectedToSomething(graph, counterpart))
\r
159 return Collections.emptyList();
\r
165 private boolean isConnectedToSomething(ReadGraph graph, Resource flag) throws DatabaseException {
\r
166 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
167 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
168 for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
\r
169 Resource cntr = graph.getPossibleObject(connector, DIA.AreConnected);
\r
170 Resource conn = ConnectionUtil.getConnection(graph, cntr);
\r
171 if (cntr == null || conn == null)
\r
178 private EdgeResource getEdge(ReadGraph graph, Object object) throws DatabaseException {
\r
179 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
181 Resource connection = null;
\r
182 EdgeResource edge = AdaptionUtils.adaptToSingle(object, EdgeResource.class);
\r
184 //connection = ConnectionUtil.getConnection(graph, edge);
\r
187 connection = AdaptionUtils.adaptToSingle(object, Resource.class);
\r
190 if (connection != null && graph.isInstanceOf(connection, DiagramResource.getInstance(graph).Connection)) {
\r
191 Collection<Resource> connectors = graph.getObjects(connection, DIA.HasConnector);
\r
192 Collection<Resource> branchPoints = graph.getObjects(connection, DIA.HasBranchPoint);
\r
193 if (branchPoints.isEmpty() && connectors.size() == 2) {
\r
194 Iterator<Resource> it = connectors.iterator();
\r
195 Resource connector1 = it.next();
\r
196 Resource connector2 = it.next();
\r
197 return new EdgeResource(connector1, connector2);
\r
204 public static abstract class Helper extends Action {
\r
206 protected final Session session;
\r
207 protected final ICanvasContext context;
\r
209 public Helper(String label, Session session, ICanvasContext context) {
\r
211 this.session = session;
\r
212 this.context = context;
\r
216 public void run() {
\r
218 session.syncRequest(new WriteRequest() {
\r
220 public void perform(WriteGraph graph) throws DatabaseException {
\r
221 graph.markUndoPoint();
\r
222 performAction(graph);
\r
225 ThreadUtils.asyncExec(context.getThreadAccess(), new Runnable() {
\r
227 public void run() {
\r
228 if (context.isDisposed())
\r
230 Selection selection = context.getAtMostOneItemOfClass(Selection.class);
\r
231 if (selection != null) {
\r
232 // This prevents workbench selection from being left over.
\r
233 // Also prevents scene graph crap from being left on the screen.
\r
234 selection.clear(0);
\r
238 } catch (DatabaseException e) {
\r
239 ExceptionUtils.logError(e);
\r
246 protected abstract void performAction(WriteGraph graph) throws DatabaseException;
\r
250 public static class Split extends Helper {
\r
251 private final Point2D splitCanvasPos;
\r
252 private final IElement edgeElement;
\r
253 private final EdgeResource edge;
\r
255 public Split(Session session, ICanvasContext context, Point2D splitCanvasPos, IElement edgeElement, EdgeResource edge) {
\r
256 super("Split Connection", session, context);
\r
257 setImageDescriptor(Activator.LINK_BREAK_ICON);
\r
258 this.splitCanvasPos = splitCanvasPos;
\r
259 this.edgeElement = edgeElement;
\r
264 protected void performAction(WriteGraph graph) throws DatabaseException {
\r
265 new Splitter(graph).split(graph, edgeElement, edge, splitCanvasPos);
\r
269 public static class SplitRouteGraph extends Helper {
\r
270 private final Point2D splitCanvasPos;
\r
271 private final Resource connection;
\r
273 public SplitRouteGraph(Session session, ICanvasContext context, Point2D splitCanvasPos, Resource connection) {
\r
274 super("Split Connection", session, context);
\r
275 setImageDescriptor(Activator.LINK_BREAK_ICON);
\r
276 this.splitCanvasPos = splitCanvasPos;
\r
277 this.connection = connection;
\r
281 protected void performAction(WriteGraph graph) throws DatabaseException {
\r
282 Command command = Commands.get(graph, "Simantics/Diagram/splitConnection");
\r
283 command.execute(graph, graph.syncRequest(new IndexRoot(connection)),
\r
284 connection, splitCanvasPos.getX(), splitCanvasPos.getY());
\r
288 public static class Join extends Helper {
\r
289 private final Collection<Resource> flags;
\r
291 public Join(Session session, ICanvasContext context, Collection<Resource> flags) {
\r
292 super("Join Flags", session, context);
\r
293 setImageDescriptor(Activator.LINK_ICON);
\r
294 this.flags = flags;
\r
298 protected void performAction(WriteGraph graph) throws DatabaseException {
\r
299 Command command = Commands.get(graph, "Simantics/Diagram/joinFlagsLocal");
\r
300 command.execute(graph, graph.syncRequest(new IndexRoot(flags.iterator().next())), flags);
\r