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