-/*******************************************************************************\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.participant;\r
-\r
-import static org.simantics.g2d.diagram.handler.PickRequest.PickFilter.FILTER_CONNECTIONS;\r
-import static org.simantics.g2d.diagram.handler.PickRequest.PickFilter.FILTER_CONNECTION_EDGES;\r
-import static org.simantics.g2d.diagram.handler.PickRequest.PickFilter.FILTER_NODES;\r
-\r
-import java.awt.Shape;\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.Line2D;\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.Comparator;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.concurrent.atomic.AtomicReference;\r
-\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\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.stubs.DiagramResource;\r
-import org.simantics.diagram.ui.DiagramModelHints;\r
-import org.simantics.g2d.canvas.ICanvasContext;\r
-import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
-import org.simantics.g2d.diagram.DiagramHints;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.handler.DataElementMap;\r
-import org.simantics.g2d.diagram.handler.PickContext;\r
-import org.simantics.g2d.diagram.handler.PickRequest;\r
-import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy;\r
-import org.simantics.g2d.diagram.handler.PickRequest.PickSorter;\r
-import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
-import org.simantics.g2d.diagram.participant.Selection;\r
-import org.simantics.g2d.diagram.participant.pointertool.AbstractMode;\r
-import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;\r
-import org.simantics.g2d.diagram.participant.pointertool.TranslateMode;\r
-import org.simantics.g2d.element.ElementUtils;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.element.handler.Children;\r
-import org.simantics.g2d.participant.TransformUtil;\r
-import org.simantics.g2d.participant.WorkbenchStatusLine;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent;\r
-import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
-import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.utils.datastructures.hints.HintListenerAdapter;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-import org.simantics.utils.datastructures.hints.IHintListener;\r
-import org.simantics.utils.datastructures.hints.IHintObservable;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public class ConnectionEditingSupport extends AbstractDiagramParticipant {\r
-\r
- private static final boolean DEBUG = false;\r
-\r
- private static final int TOOL_PRIORITY = 100;\r
-\r
- @Dependency PointerInteractor pi;\r
- @Dependency PickContext pickContext;\r
- @Dependency Selection selection;\r
- @Dependency WorkbenchStatusLine statusLine;\r
-\r
- private static final PickSorter NODES_LAST = new PickSorter() {\r
- @Override\r
- public void sort(List<IElement> elements) {\r
- Collections.sort(elements, new Comparator<IElement>() {\r
- @Override\r
- public int compare(IElement e1, IElement e2) {\r
- boolean is1 = FILTER_NODES.accept(e1);\r
- boolean is2 = FILTER_NODES.accept(e2);\r
- if (!is1 && is2)\r
- return -1;\r
- if (is1 && !is2)\r
- return 1;\r
- return 0;\r
- }\r
- });\r
- }\r
- };\r
-\r
- private boolean routePointsEnabled() {\r
- return Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS));\r
- }\r
-\r
- @EventHandler(priority = TOOL_PRIORITY)\r
- public boolean handleMouse(MouseEvent e) {\r
- if (!routePointsEnabled())\r
- return false;\r
- if (e instanceof MouseButtonPressedEvent)\r
- return handlePress((MouseButtonPressedEvent) e);\r
- return false;\r
- }\r
-\r
- private boolean handlePress(MouseButtonPressedEvent me) {\r
- if (me.button != MouseEvent.LEFT_BUTTON || me.hasAnyModifier(MouseEvent.ALL_MODIFIERS_MASK))\r
- return false;\r
-\r
- //System.out.println("button pressed: " + me);\r
-\r
- Shape shape = pi.getCanvasPickShape(me.controlPosition);\r
- if (shape == null)\r
- return false;\r
-\r
- PickRequest req = new PickRequest(shape);\r
- req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;\r
- req.pickFilter = null;\r
- req.pickSorter = NODES_LAST;\r
-\r
- List<IElement> pick = new ArrayList<IElement>();\r
- pickContext.pick(diagram, req, pick);\r
-\r
- if (pick.isEmpty())\r
- return false;\r
-\r
- //System.out.println("selection pick returns " + pick);\r
-\r
- // If current mouse selection contains only a connection edge or\r
- // complete connection and pick result contains the same connection or\r
- // edge as the first hit, start dragging new route point.\r
- Set<IElement> sel = selection.getSelection(me.mouseId);\r
- if (!Collections.disjoint(pick, sel)) {\r
- if (sel.size() == 1) {\r
- IElement e = sel.iterator().next();\r
- if (FILTER_CONNECTIONS.accept(e) || FILTER_CONNECTION_EDGES.accept(e)) {\r
- IElement edge = findSingleConnectionEdge(pick, e);\r
- if (edge != null) {\r
- getContext().add(new ConnectionRoutingMode(me.mouseId, edge));\r
- return true;\r
- }\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- IElement edge = findSingleConnectionEdge(pick, null);\r
- if (edge != null) {\r
- getContext().add(new ConnectionRoutingMode(me.mouseId, edge));\r
- return true;\r
- }\r
-\r
- return false;\r
- }\r
-\r
- /**\r
- * @param pick\r
- * @param selected\r
- * @return\r
- */\r
- private IElement findSingleConnectionEdge(List<IElement> pick, IElement selected) {\r
- for (int i = pick.size() - 1; i >= 0; --i) {\r
- IElement p = pick.get(i);\r
- boolean pickedSelected = selected == null ? true : p == selected;\r
- if (FILTER_NODES.accept(p))\r
- return null;\r
- if (pickedSelected && FILTER_CONNECTION_EDGES.accept(p)) {\r
- return p;\r
- }\r
- }\r
- for (int i = pick.size() - 1; i >= 0; --i) {\r
- IElement p = pick.get(i);\r
- boolean pickedSelected = selected == null ? true : p == selected;\r
- if (FILTER_CONNECTIONS.accept(p)) {\r
- Children ch = p.getElementClass().getAtMostOneItemOfClass(Children.class);\r
- if (ch == null)\r
- return null;\r
-\r
- Collection<IElement> children = ch.getChildren(p, null);\r
- int childCount = children.size();\r
- if (childCount == 1) {\r
- for (IElement child : children) {\r
- if (pickedSelected && FILTER_CONNECTION_EDGES.accept(child))\r
- return child;\r
- }\r
- } else if (childCount > 1) {\r
- for (IElement child : children) {\r
- if (pickedSelected && FILTER_CONNECTION_EDGES.accept(child) && pick.contains(child))\r
- return child;\r
- }\r
- }\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- static class ConnectionRoutingMode extends AbstractMode {\r
-\r
- @Dependency TransformUtil tr;\r
- @Dependency Selection sel;\r
-\r
- private boolean dragging;\r
- private final IElement edge;\r
-\r
- public ConnectionRoutingMode(int mouseId, IElement edge) {\r
- super(mouseId);\r
- if (DEBUG)\r
- System.out.println("Start routing mode (" + mouseId + ")");\r
- this.edge = edge;\r
- }\r
-\r
- @Override\r
- public void addedToContext(ICanvasContext ctx) {\r
- super.addedToContext(ctx);\r
- if (DEBUG)\r
- System.out.println(this + " added");\r
- }\r
-\r
- @Override\r
- public void removedFromContext(ICanvasContext ctx) {\r
- if (DEBUG)\r
- System.out.println(this + " removed");\r
- super.removedFromContext(ctx);\r
- }\r
-\r
- @Override\r
- protected void onDiagramSet(IDiagram newDiagram, IDiagram oldDiagram) {\r
- if (oldDiagram != null) {\r
- oldDiagram.removeKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, diagramHintListener);\r
- }\r
- if (newDiagram != null) {\r
- newDiagram.addKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, diagramHintListener);\r
- }\r
- }\r
-\r
- @EventHandler(priority = TOOL_PRIORITY + 10)\r
- public boolean handleMouse(MouseEvent e) {\r
- if (!isModeMouse(e))\r
- return false;\r
-\r
- //System.out.println("mouse event: " + e);\r
-\r
- if (e instanceof MouseMovedEvent)\r
- return handleMove((MouseMovedEvent) e);\r
- if (e instanceof MouseDragBegin)\r
- return handleDrag((MouseDragBegin) e);\r
- if (e instanceof MouseButtonReleasedEvent)\r
- return handleRelease((MouseButtonReleasedEvent) e);\r
-\r
- // Ignore all other events\r
- return true;\r
- }\r
-\r
- private boolean handleDrag(MouseDragBegin e) {\r
- // Mark dragging as started.\r
- dragging = true;\r
- splitConnection(e.startCanvasPos, tr.controlToCanvas(e.controlPosition, null));\r
- return true;\r
- }\r
-\r
- private boolean handleMove(MouseMovedEvent e) {\r
- if (!dragging)\r
- return true;\r
- if (DEBUG)\r
- System.out.println("routing move: " + e);\r
- return false;\r
- }\r
-\r
- private boolean handleRelease(MouseButtonReleasedEvent e) {\r
-// setDirty();\r
- remove();\r
- return false;\r
- }\r
-\r
- boolean splitConnection(final Point2D startingPos, Point2D currentPos) {\r
- final IDiagram diagram = ElementUtils.peekDiagram(edge);\r
- if (diagram == null)\r
- return false;\r
- final EdgeResource segment = (EdgeResource) ElementUtils.getObject(edge);\r
- if (segment == null)\r
- return false;\r
-\r
- Point2D snapPos = new Point2D.Double(startingPos.getX(), startingPos.getY());\r
- ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);\r
- if (snap != null)\r
- snap.snap(snapPos);\r
-\r
- final AffineTransform splitPos = AffineTransform.getTranslateInstance(snapPos.getX(), snapPos.getY());\r
- final AtomicReference<Resource> newBp = new AtomicReference<Resource>();\r
-\r
- try {\r
- SimanticsUI.getSession().syncRequest(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- DiagramResource DIA = DiagramResource.getInstance(graph);\r
-\r
- // Split the edge with a new branch point\r
- ConnectionUtil cu = new ConnectionUtil(graph);\r
- Resource bp = cu.split(segment, splitPos);\r
-\r
- Line2D nearestLine = ConnectionUtil.resolveNearestEdgeLineSegment(startingPos, edge);\r
- if (nearestLine != null) {\r
- double angle = Math.atan2(\r
- Math.abs(nearestLine.getY2() - nearestLine.getY1()),\r
- Math.abs(nearestLine.getX2() - nearestLine.getX1())\r
- );\r
-\r
- if (angle >= 0 && angle < Math.PI / 4) {\r
- graph.claim(bp, DIA.Horizontal, bp);\r
- } else if (angle > Math.PI / 4 && angle <= Math.PI / 2) {\r
- graph.claim(bp, DIA.Vertical, bp);\r
- }\r
- }\r
-\r
- newBp.set(bp);\r
- }\r
-\r
- });\r
-\r
- dragData.set(new DragData(Collections.singleton(newBp.get()), startingPos, currentPos));\r
-\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- }\r
-\r
- return false;\r
- }\r
-\r
- static class DragData {\r
- Set<?> data;\r
- Point2D startingPoint;\r
- Point2D currentPoint;\r
- public DragData(Set<?> data, Point2D startingPoint, Point2D currentPoint) {\r
- this.data = data;\r
- this.startingPoint = startingPoint;\r
- this.currentPoint = currentPoint;\r
- }\r
- }\r
-\r
- private final AtomicReference<DragData> dragData = new AtomicReference<DragData>();\r
-\r
- IHintListener diagramHintListener = new HintListenerAdapter() {\r
- @Override\r
- public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
- if (isRemoved())\r
- return;\r
- if (key == DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED) {\r
- final DragData data = dragData.getAndSet(null);\r
- if (data != null) {\r
- asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- // Safety first.\r
- if (isRemoved())\r
- return;\r
- setDiagramSelectionToData(data);\r
- }\r
- });\r
- }\r
- }\r
- }\r
-\r
- private void setDiagramSelectionToData(final DragData data) {\r
- DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);\r
- if (dem != null) {\r
- final Collection<IElement> newSelection = new ArrayList<IElement>(data.data.size());\r
- for (Object datum : data.data) {\r
- IElement element = dem.getElement(diagram, datum);\r
- if (element != null) {\r
- newSelection.add(element);\r
- }\r
- }\r
-\r
- if (!newSelection.isEmpty()) {\r
- sel.setSelection(0, newSelection);\r
- getContext().add( new TranslateMode(data.startingPoint, data.currentPoint, getMouseId(), newSelection) );\r
- remove();\r
- }\r
- }\r
- }\r
- };\r
-\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.participant;
+
+import static org.simantics.g2d.diagram.handler.PickRequest.PickFilter.FILTER_CONNECTIONS;
+import static org.simantics.g2d.diagram.handler.PickRequest.PickFilter.FILTER_CONNECTION_EDGES;
+import static org.simantics.g2d.diagram.handler.PickRequest.PickFilter.FILTER_NODES;
+
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.simantics.Simantics;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.diagram.content.ConnectionUtil;
+import org.simantics.diagram.content.EdgeResource;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.ui.DiagramModelHints;
+import org.simantics.g2d.canvas.ICanvasContext;
+import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
+import org.simantics.g2d.diagram.DiagramHints;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.DataElementMap;
+import org.simantics.g2d.diagram.handler.PickContext;
+import org.simantics.g2d.diagram.handler.PickRequest;
+import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy;
+import org.simantics.g2d.diagram.handler.PickRequest.PickSorter;
+import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
+import org.simantics.g2d.diagram.participant.Selection;
+import org.simantics.g2d.diagram.participant.pointertool.AbstractMode;
+import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
+import org.simantics.g2d.diagram.participant.pointertool.TranslateMode;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.handler.Children;
+import org.simantics.g2d.participant.TransformUtil;
+import org.simantics.g2d.participant.WorkbenchStatusLine;
+import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
+import org.simantics.scenegraph.g2d.events.MouseEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
+import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
+import org.simantics.utils.datastructures.hints.HintListenerAdapter;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.datastructures.hints.IHintListener;
+import org.simantics.utils.datastructures.hints.IHintObservable;
+import org.simantics.utils.ui.ErrorLogger;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class ConnectionEditingSupport extends AbstractDiagramParticipant {
+
+ private static final boolean DEBUG = false;
+
+ private static final int TOOL_PRIORITY = 100;
+
+ @Dependency PointerInteractor pi;
+ @Dependency PickContext pickContext;
+ @Dependency Selection selection;
+ @Dependency WorkbenchStatusLine statusLine;
+
+ private static final PickSorter NODES_LAST = new PickSorter() {
+ @Override
+ public void sort(List<IElement> elements) {
+ Collections.sort(elements, new Comparator<IElement>() {
+ @Override
+ public int compare(IElement e1, IElement e2) {
+ boolean is1 = FILTER_NODES.accept(e1);
+ boolean is2 = FILTER_NODES.accept(e2);
+ if (!is1 && is2)
+ return -1;
+ if (is1 && !is2)
+ return 1;
+ return 0;
+ }
+ });
+ }
+ };
+
+ private boolean routePointsEnabled() {
+ return Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS));
+ }
+
+ @EventHandler(priority = TOOL_PRIORITY)
+ public boolean handleMouse(MouseEvent e) {
+ if (!routePointsEnabled())
+ return false;
+ if (e instanceof MouseButtonPressedEvent)
+ return handlePress((MouseButtonPressedEvent) e);
+ return false;
+ }
+
+ private boolean handlePress(MouseButtonPressedEvent me) {
+ if (me.button != MouseEvent.LEFT_BUTTON || me.hasAnyModifier(MouseEvent.ALL_MODIFIERS_MASK))
+ return false;
+
+ //System.out.println("button pressed: " + me);
+
+ Shape shape = pi.getCanvasPickShape(me.controlPosition);
+ if (shape == null)
+ return false;
+
+ PickRequest req = new PickRequest(shape).context(getContext());
+ req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
+ req.pickFilter = null;
+ req.pickSorter = NODES_LAST;
+
+ List<IElement> pick = new ArrayList<IElement>();
+ pickContext.pick(diagram, req, pick);
+
+ if (pick.isEmpty())
+ return false;
+
+ //System.out.println("selection pick returns " + pick);
+
+ // If current mouse selection contains only a connection edge or
+ // complete connection and pick result contains the same connection or
+ // edge as the first hit, start dragging new route point.
+ Set<IElement> sel = selection.getSelection(me.mouseId);
+ if (!Collections.disjoint(pick, sel)) {
+ if (sel.size() == 1) {
+ IElement e = sel.iterator().next();
+ if (FILTER_CONNECTIONS.accept(e) || FILTER_CONNECTION_EDGES.accept(e)) {
+ IElement edge = findSingleConnectionEdge(pick, e);
+ if (edge != null) {
+ getContext().add(new ConnectionRoutingMode(me.mouseId, edge));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ IElement edge = findSingleConnectionEdge(pick, null);
+ if (edge != null) {
+ getContext().add(new ConnectionRoutingMode(me.mouseId, edge));
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param pick
+ * @param selected
+ * @return
+ */
+ private IElement findSingleConnectionEdge(List<IElement> pick, IElement selected) {
+ for (int i = pick.size() - 1; i >= 0; --i) {
+ IElement p = pick.get(i);
+ boolean pickedSelected = selected == null ? true : p == selected;
+ if (FILTER_NODES.accept(p))
+ return null;
+ if (pickedSelected && FILTER_CONNECTION_EDGES.accept(p)) {
+ return p;
+ }
+ }
+ for (int i = pick.size() - 1; i >= 0; --i) {
+ IElement p = pick.get(i);
+ boolean pickedSelected = selected == null ? true : p == selected;
+ if (FILTER_CONNECTIONS.accept(p)) {
+ Children ch = p.getElementClass().getAtMostOneItemOfClass(Children.class);
+ if (ch == null)
+ return null;
+
+ Collection<IElement> children = ch.getChildren(p, null);
+ int childCount = children.size();
+ if (childCount == 1) {
+ for (IElement child : children) {
+ if (pickedSelected && FILTER_CONNECTION_EDGES.accept(child))
+ return child;
+ }
+ } else if (childCount > 1) {
+ for (IElement child : children) {
+ if (pickedSelected && FILTER_CONNECTION_EDGES.accept(child) && pick.contains(child))
+ return child;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ static class ConnectionRoutingMode extends AbstractMode {
+
+ @Dependency TransformUtil tr;
+ @Dependency Selection sel;
+
+ private boolean dragging;
+ private final IElement edge;
+
+ public ConnectionRoutingMode(int mouseId, IElement edge) {
+ super(mouseId);
+ if (DEBUG)
+ System.out.println("Start routing mode (" + mouseId + ")");
+ this.edge = edge;
+ }
+
+ @Override
+ public void addedToContext(ICanvasContext ctx) {
+ super.addedToContext(ctx);
+ if (DEBUG)
+ System.out.println(this + " added");
+ }
+
+ @Override
+ public void removedFromContext(ICanvasContext ctx) {
+ if (DEBUG)
+ System.out.println(this + " removed");
+ super.removedFromContext(ctx);
+ }
+
+ @Override
+ protected void onDiagramSet(IDiagram newDiagram, IDiagram oldDiagram) {
+ if (oldDiagram != null) {
+ oldDiagram.removeKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, diagramHintListener);
+ }
+ if (newDiagram != null) {
+ newDiagram.addKeyHintListener(DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED, diagramHintListener);
+ }
+ }
+
+ @EventHandler(priority = TOOL_PRIORITY + 10)
+ public boolean handleMouse(MouseEvent e) {
+ if (!isModeMouse(e))
+ return false;
+
+ //System.out.println("mouse event: " + e);
+
+ if (e instanceof MouseMovedEvent)
+ return handleMove((MouseMovedEvent) e);
+ if (e instanceof MouseDragBegin)
+ return handleDrag((MouseDragBegin) e);
+ if (e instanceof MouseButtonReleasedEvent)
+ return handleRelease((MouseButtonReleasedEvent) e);
+
+ // Ignore all other events
+ return true;
+ }
+
+ private boolean handleDrag(MouseDragBegin e) {
+ // Mark dragging as started.
+ dragging = true;
+ splitConnection(e.startCanvasPos, tr.controlToCanvas(e.controlPosition, null));
+ return true;
+ }
+
+ private boolean handleMove(MouseMovedEvent e) {
+ if (!dragging)
+ return true;
+ if (DEBUG)
+ System.out.println("routing move: " + e);
+ return false;
+ }
+
+ private boolean handleRelease(MouseButtonReleasedEvent e) {
+// setDirty();
+ remove();
+ return false;
+ }
+
+ boolean splitConnection(final Point2D startingPos, Point2D currentPos) {
+ final IDiagram diagram = ElementUtils.peekDiagram(edge);
+ if (diagram == null)
+ return false;
+ final EdgeResource segment = (EdgeResource) ElementUtils.getObject(edge);
+ if (segment == null)
+ return false;
+
+ Point2D snapPos = new Point2D.Double(startingPos.getX(), startingPos.getY());
+ ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);
+ if (snap != null)
+ snap.snap(snapPos);
+
+ final AffineTransform splitPos = AffineTransform.getTranslateInstance(snapPos.getX(), snapPos.getY());
+ final AtomicReference<Resource> newBp = new AtomicReference<Resource>();
+
+ try {
+ Simantics.getSession().syncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+
+ // Split the edge with a new branch point
+ ConnectionUtil cu = new ConnectionUtil(graph);
+ Resource bp = cu.split(segment, splitPos);
+
+ Line2D nearestLine = ConnectionUtil.resolveNearestEdgeLineSegment(startingPos, edge);
+ if (nearestLine != null) {
+ double angle = Math.atan2(
+ Math.abs(nearestLine.getY2() - nearestLine.getY1()),
+ Math.abs(nearestLine.getX2() - nearestLine.getX1())
+ );
+
+ if (angle >= 0 && angle < Math.PI / 4) {
+ graph.claim(bp, DIA.Horizontal, bp);
+ } else if (angle > Math.PI / 4 && angle <= Math.PI / 2) {
+ graph.claim(bp, DIA.Vertical, bp);
+ }
+ }
+
+ newBp.set(bp);
+ }
+
+ });
+
+ dragData.set(new DragData(Collections.singleton(newBp.get()), startingPos, currentPos));
+
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+
+ return false;
+ }
+
+ static class DragData {
+ Set<?> data;
+ Point2D startingPoint;
+ Point2D currentPoint;
+ public DragData(Set<?> data, Point2D startingPoint, Point2D currentPoint) {
+ this.data = data;
+ this.startingPoint = startingPoint;
+ this.currentPoint = currentPoint;
+ }
+ }
+
+ private final AtomicReference<DragData> dragData = new AtomicReference<DragData>();
+
+ IHintListener diagramHintListener = new HintListenerAdapter() {
+ @Override
+ public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
+ if (isRemoved())
+ return;
+ if (key == DiagramModelHints.KEY_DIAGRAM_CONTENTS_UPDATED) {
+ final DragData data = dragData.getAndSet(null);
+ if (data != null) {
+ asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ // Safety first.
+ if (isRemoved())
+ return;
+ setDiagramSelectionToData(data);
+ }
+ });
+ }
+ }
+ }
+
+ private void setDiagramSelectionToData(final DragData data) {
+ DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);
+ if (dem != null) {
+ final Collection<IElement> newSelection = new ArrayList<IElement>(data.data.size());
+ for (Object datum : data.data) {
+ IElement element = dem.getElement(diagram, datum);
+ if (element != null) {
+ newSelection.add(element);
+ }
+ }
+
+ if (!newSelection.isEmpty()) {
+ sel.setSelection(0, newSelection);
+ getContext().add( new TranslateMode(data.startingPoint, data.currentPoint, getMouseId(), newSelection) );
+ remove();
+ }
+ }
+ }
+ };
+
+ }
+
+}