X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fparticipant%2FConnectionEditingSupport.java;h=fe11570fe11f770374c845168e19a3ec4b457ce1;hp=755f5230dbc3f16bd09b6ce2881b4a9b5075b9a0;hb=25f90625263911a40f785edbeb8ca44b3db23911;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionEditingSupport.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionEditingSupport.java index 755f5230d..fe11570fe 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionEditingSupport.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionEditingSupport.java @@ -1,395 +1,395 @@ -/******************************************************************************* - * 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.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.MouseEvent; -import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; -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.ui.SimanticsUI; -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 elements) { - Collections.sort(elements, new Comparator() { - @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); - req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS; - req.pickFilter = null; - req.pickSorter = NODES_LAST; - - List pick = new ArrayList(); - 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 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 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 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 newBp = new AtomicReference(); - - try { - SimanticsUI.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 = new AtomicReference(); - - 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 newSelection = new ArrayList(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(); - } - } - } - }; - - } - -} +/******************************************************************************* + * 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 elements) { + Collections.sort(elements, new Comparator() { + @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 pick = new ArrayList(); + 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 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 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 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 newBp = new AtomicReference(); + + 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 = new AtomicReference(); + + 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 newSelection = new ArrayList(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(); + } + } + } + }; + + } + +}