1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.diagram.handler;
14 import java.awt.geom.Point2D;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Iterator;
21 import org.eclipse.jface.action.Action;
22 import org.eclipse.jface.action.ActionContributionItem;
23 import org.eclipse.jface.action.IContributionItem;
24 import org.eclipse.swt.widgets.Menu;
25 import org.eclipse.ui.IWorkbenchPart;
26 import org.simantics.db.ReadGraph;
27 import org.simantics.db.Resource;
28 import org.simantics.db.Session;
29 import org.simantics.db.WriteGraph;
30 import org.simantics.db.common.request.IndexRoot;
31 import org.simantics.db.common.request.WriteRequest;
32 import org.simantics.db.common.utils.OrderedSetUtils;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.diagram.content.ConnectionUtil;
35 import org.simantics.diagram.content.EdgeResource;
36 import org.simantics.diagram.flag.FlagUtil;
37 import org.simantics.diagram.flag.Splitter;
38 import org.simantics.diagram.internal.Activator;
39 import org.simantics.diagram.stubs.DiagramResource;
40 import org.simantics.g2d.canvas.ICanvasContext;
41 import org.simantics.g2d.diagram.DiagramHints;
42 import org.simantics.g2d.diagram.participant.Selection;
43 import org.simantics.g2d.element.IElement;
44 import org.simantics.scl.commands.Command;
45 import org.simantics.scl.commands.Commands;
46 import org.simantics.structural.stubs.StructuralResource2;
47 import org.simantics.ui.contribution.DynamicMenuContribution;
48 import org.simantics.utils.threads.ThreadUtils;
49 import org.simantics.utils.ui.AdaptionUtils;
50 import org.simantics.utils.ui.ExceptionUtils;
51 import org.simantics.utils.ui.workbench.WorkbenchUtils;
54 * @author Tuukka Lehtonen
56 public class ConnectionSplitAndJoin extends DynamicMenuContribution {
58 private static final IContributionItem[] NONE = {};
60 private ICanvasContext canvas;
63 public void fill(Menu menu, int index) {
64 // Need to grab active part here, we're still in the SWT thread.
65 IWorkbenchPart activePart = WorkbenchUtils.getActiveWorkbenchPart();
66 if (activePart == null)
68 ICanvasContext ctx = (ICanvasContext) activePart.getAdapter(ICanvasContext.class);
74 super.fill(menu, index);
81 protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException {
82 // If selection contains:
83 // a) only diagram-locally connected flags, that each are connected to something, allow joining of those flag into connections
84 // b) a single connection edge element, allow splitting into a connected flag pair
86 Collection<Resource> localConnectedFlags = Collections.emptyList();
87 Resource routeGraphConnection = null;
88 EdgeResource edge = null;
89 if (selection.length == 1) {
90 routeGraphConnection = getRouteGraphConnection(graph, selection[0]);
91 if (routeGraphConnection == null) {
92 edge = getEdge(graph, selection[0]);
94 localConnectedFlags = getLocalConnectedFlags(graph, selection);
97 localConnectedFlags = getLocalConnectedFlags(graph, selection);
100 if (!localConnectedFlags.isEmpty()) {
101 return new IContributionItem[] {
102 new ActionContributionItem(new Join(graph.getSession(), canvas, localConnectedFlags))
104 } else if (edge != null) {
105 Selection sel = canvas.getAtMostOneItemOfClass(Selection.class);
108 Set<IElement> elems = sel.getSelection(0);
109 if (elems.size() != 1)
111 IElement edgeElement = ConnectionUtil.getSingleEdge(elems.iterator().next());
112 if (edgeElement == null)
114 Point2D canvasPosition = canvas.getHintStack().getHint(DiagramHints.POPUP_MENU_CANVAS_POSITION);
115 if (canvasPosition == null)
118 return new IContributionItem[] {
119 new ActionContributionItem(new Split(graph.getSession(), canvas, canvasPosition, edgeElement, edge))
121 } else if (routeGraphConnection != null) {
122 Selection sel = canvas.getAtMostOneItemOfClass(Selection.class);
125 Set<IElement> elems = sel.getSelection(0);
126 if (elems.size() != 1)
128 Point2D canvasPosition = canvas.getHintStack().getHint(DiagramHints.POPUP_MENU_CANVAS_POSITION);
129 if (canvasPosition == null)
132 return new IContributionItem[] {
133 new ActionContributionItem(new SplitRouteGraph(graph.getSession(), canvas, canvasPosition, routeGraphConnection))
139 private Resource getRouteGraphConnection(ReadGraph graph, Object object) throws DatabaseException {
140 DiagramResource DIA = DiagramResource.getInstance(graph);
141 Resource connection = AdaptionUtils.adaptToSingle(object, Resource.class);
142 if (connection != null && graph.isInstanceOf(connection, DIA.RouteGraphConnection))
147 private Collection<Resource> getLocalConnectedFlags(ReadGraph graph, Object[] selection) throws DatabaseException {
148 DiagramResource DIA = DiagramResource.getInstance(graph);
149 ArrayList<Resource> result = new ArrayList<Resource>(4);
150 for (Object s : selection) {
151 Resource r = AdaptionUtils.adaptToSingle(s, Resource.class);
152 if (r == null || !graph.isInstanceOf(r, DIA.Flag))
153 return Collections.emptyList();
154 if (!isConnectedToSomething(graph, r))
155 return Collections.emptyList();
156 Collection<Resource> counterparts = FlagUtil.getCounterparts(graph, r);
157 if (counterparts.isEmpty())
158 return Collections.emptyList();
159 Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, r, DIA.Diagram);
160 for (Resource counterpart : counterparts) {
161 boolean joinedWithinSingleDiagram = !Collections.disjoint(flagDiagrams,
162 OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram));
163 if (!joinedWithinSingleDiagram)
164 return Collections.emptyList();
165 if (!isConnectedToSomething(graph, counterpart))
166 return Collections.emptyList();
173 private boolean isConnectedToSomething(ReadGraph graph, Resource flag) throws DatabaseException {
174 DiagramResource DIA = DiagramResource.getInstance(graph);
175 StructuralResource2 STR = StructuralResource2.getInstance(graph);
176 for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
177 Resource cntr = graph.getPossibleObject(connector, DIA.AreConnected);
178 Resource conn = ConnectionUtil.getConnection(graph, cntr);
179 if (cntr == null || conn == null)
186 private EdgeResource getEdge(ReadGraph graph, Object object) throws DatabaseException {
187 DiagramResource DIA = DiagramResource.getInstance(graph);
189 Resource connection = null;
190 EdgeResource edge = AdaptionUtils.adaptToSingle(object, EdgeResource.class);
192 //connection = ConnectionUtil.getConnection(graph, edge);
195 connection = AdaptionUtils.adaptToSingle(object, Resource.class);
198 if (connection != null && graph.isInstanceOf(connection, DiagramResource.getInstance(graph).Connection)) {
199 Collection<Resource> connectors = graph.getObjects(connection, DIA.HasConnector);
200 Collection<Resource> branchPoints = graph.getObjects(connection, DIA.HasBranchPoint);
201 if (branchPoints.isEmpty() && connectors.size() == 2) {
202 Iterator<Resource> it = connectors.iterator();
203 Resource connector1 = it.next();
204 Resource connector2 = it.next();
205 return new EdgeResource(connector1, connector2);
212 public static abstract class Helper extends Action {
214 protected final Session session;
215 protected final ICanvasContext context;
217 public Helper(String label, Session session, ICanvasContext context) {
219 this.session = session;
220 this.context = context;
226 session.syncRequest(new WriteRequest() {
228 public void perform(WriteGraph graph) throws DatabaseException {
229 graph.markUndoPoint();
230 performAction(graph);
233 ThreadUtils.asyncExec(context.getThreadAccess(), new Runnable() {
236 if (context.isDisposed())
238 Selection selection = context.getAtMostOneItemOfClass(Selection.class);
239 if (selection != null) {
240 // This prevents workbench selection from being left over.
241 // Also prevents scene graph crap from being left on the screen.
246 } catch (DatabaseException e) {
247 ExceptionUtils.logError(e);
254 protected abstract void performAction(WriteGraph graph) throws DatabaseException;
258 public static class Split extends Helper {
259 private final Point2D splitCanvasPos;
260 private final IElement edgeElement;
261 private final EdgeResource edge;
263 public Split(Session session, ICanvasContext context, Point2D splitCanvasPos, IElement edgeElement, EdgeResource edge) {
264 super("Split Connection", session, context);
265 setImageDescriptor(Activator.LINK_BREAK_ICON);
266 this.splitCanvasPos = splitCanvasPos;
267 this.edgeElement = edgeElement;
272 protected void performAction(WriteGraph graph) throws DatabaseException {
273 new Splitter(graph).split(graph, edgeElement, edge, splitCanvasPos);
277 public static class SplitRouteGraph extends Helper {
278 private final Point2D splitCanvasPos;
279 private final Resource connection;
281 public SplitRouteGraph(Session session, ICanvasContext context, Point2D splitCanvasPos, Resource connection) {
282 super("Split Connection", session, context);
283 setImageDescriptor(Activator.LINK_BREAK_ICON);
284 this.splitCanvasPos = splitCanvasPos;
285 this.connection = connection;
289 protected void performAction(WriteGraph graph) throws DatabaseException {
290 Command command = Commands.get(graph, "Simantics/Diagram/splitConnection");
291 command.execute(graph, graph.syncRequest(new IndexRoot(connection)),
292 connection, splitCanvasPos.getX(), splitCanvasPos.getY());
296 public static class Join extends Helper {
297 private final Collection<Resource> flags;
299 public Join(Session session, ICanvasContext context, Collection<Resource> flags) {
300 super("Join Flags", session, context);
301 setImageDescriptor(Activator.LINK_ICON);
306 protected void performAction(WriteGraph graph) throws DatabaseException {
307 Command command = Commands.get(graph, "Simantics/Diagram/joinFlagsLocal");
308 command.execute(graph, graph.syncRequest(new IndexRoot(flags.iterator().next())), flags);