import org.simantics.g2d.routing.IRouter2;\r
import org.simantics.g2d.routing.TrivialRouter2;\r
import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
import org.simantics.scenegraph.g2d.nodes.ShapeNode;\r
import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;\r
import org.simantics.sysdyn.SysdynResource;\r
import org.simantics.sysdyn.ui.editor.routing.FlowRouter;\r
import org.simantics.sysdyn.ui.elements.CloudFactory;\r
+import org.simantics.sysdyn.ui.elements.SysdynElementHints;\r
import org.simantics.sysdyn.ui.elements.ValveFactory.ValveSceneGraph;\r
import org.simantics.sysdyn.ui.elements.connections.ConnectionClasses;\r
import org.simantics.ui.SimanticsUI;\r
import org.simantics.utils.datastructures.Callback;\r
import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.ui.ErrorLogger;\r
import org.simantics.utils.ui.ExceptionUtils;\r
\r
public class SysdynConnectTool extends ConnectTool2 {\r
- \r
- public SysdynConnectTool(TerminalInfo startTerminal, int mouseId,\r
+\r
+ public SysdynConnectTool(TerminalInfo startTerminal, int mouseId,\r
Point2D startCanvasPos) {\r
super(startTerminal, mouseId, startCanvasPos);\r
}\r
\r
-\r
+ @Override\r
@SGInit\r
- public void initSG(G2DParentNode parent) {\r
- ghostNode = parent.addNode(G2DParentNode.class);\r
- ghostNode.setZIndex(PAINT_PRIORITY);\r
-\r
- ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
- pathNode.setColor(Color.BLACK);\r
- pathNode.setStroke(new BasicStroke(1f));\r
- pathNode.setScaleStroke(true);\r
- pathNode.setZIndex(0);\r
-\r
- G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
- points.setZIndex(1);\r
-\r
- updateSG();\r
- }\r
-\r
- \r
- protected TerminalInfo createFlag(EdgeEnd connectionEnd) {\r
- ElementClass flagClass = elementClassProvider.get(ElementClasses.FLAG);\r
- IElement e = Element.spawnNew(flagClass);\r
-\r
- e.setHint(FlagClass.KEY_FLAG_TYPE, endToFlagType(connectionEnd));\r
- e.setHint(FlagClass.KEY_FLAG_MODE, FlagClass.Mode.Internal);\r
-\r
- TerminalInfo ti = new TerminalInfo();\r
- ti.e = e;\r
- \r
- // start: this part changed to support overlapping terminals\r
+ public void initSG(G2DParentNode parent) {\r
+ ghostNode = parent.addNode(G2DParentNode.class);\r
+ ghostNode.setZIndex(PAINT_PRIORITY);\r
+\r
+ ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
+ pathNode.setColor(Color.BLACK);\r
+ pathNode.setStroke(new BasicStroke(1f));\r
+ pathNode.setScaleStroke(true);\r
+ pathNode.setZIndex(0);\r
+\r
+ G2DParentNode points = ghostNode.getOrCreateNode("points", G2DParentNode.class);\r
+ points.setZIndex(1);\r
+\r
+ updateSG();\r
+ }\r
+\r
+ @Override\r
+ protected TerminalInfo createFlag(EdgeEnd connectionEnd) {\r
+ ElementClass flagClass = elementClassProvider.get(ElementClasses.FLAG);\r
+ IElement e = Element.spawnNew(flagClass);\r
+\r
+ e.setHint(FlagClass.KEY_FLAG_TYPE, endToFlagType(connectionEnd));\r
+ e.setHint(FlagClass.KEY_FLAG_MODE, FlagClass.Mode.Internal);\r
+\r
+ TerminalInfo ti = new TerminalInfo();\r
+ ti.e = e;\r
+\r
+ // start: this part changed to support overlapping terminals\r
ArrayList<Terminal> terminals = new ArrayList<Terminal>();\r
ElementUtils.getTerminals(e, terminals, false);\r
ti.t = terminals.get(0);\r
// end\r
- \r
- ti.posElem = TerminalUtil.getTerminalPosOnElement(e, ti.t);\r
- ti.posDia = TerminalUtil.getTerminalPosOnDiagram(e, ti.t);\r
-\r
- return ti;\r
- }\r
- \r
- static class Segment {\r
- public final ControlPoint begin;\r
- public final ControlPoint end;\r
- public Path2D path;\r
-\r
- public Segment(ControlPoint begin, ControlPoint end) {\r
- this.begin = begin;\r
- this.end = end;\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return "Segment[begin=" + begin + ", end=" + end + ", path=" + path + "]";\r
- }\r
- }\r
- \r
- private List<Segment> toSegments(Deque<ControlPoint> points) {\r
- if (points.isEmpty())\r
- return Collections.emptyList();\r
-\r
- List<Segment> segments = new ArrayList<Segment>();\r
-\r
- Iterator<ControlPoint> it = points.iterator();\r
- ControlPoint prev = it.next();\r
- while (it.hasNext()) {\r
- ControlPoint next = it.next();\r
- segments.add(new Segment(prev, next));\r
- prev = next;\r
- }\r
-\r
- return segments;\r
- }\r
- \r
- public interface SysdynConnection extends IConnection { }\r
- \r
- protected void updateSG() {\r
- if (controlPoints.isEmpty())\r
- return;\r
-\r
- // Route connection segments separately\r
- IRouter2 router = ElementUtils.getHintOrDefault(diagram, DiagramHints.ROUTE_ALGORITHM, TrivialRouter2.INSTANCE);\r
- final List<Segment> segments = toSegments(controlPoints);\r
- //System.out.println("controlpoints: " + controlPoints);\r
- //System.out.println("segments: " + segments);\r
- router.route(new SysdynConnection() {\r
- @Override\r
- public Collection<? extends Object> getSegments() {\r
- return segments;\r
- }\r
-\r
- @Override\r
- public Connector getBegin(Object seg) {\r
- return getConnector(((Segment) seg).begin);\r
- }\r
-\r
- @Override\r
- public Connector getEnd(Object seg) {\r
- return getConnector(((Segment) seg).end);\r
- }\r
-\r
- private Connector getConnector(ControlPoint cp) {\r
- Connector c = new Connector();\r
- c.x = cp.getPosition().getX();\r
- c.y = cp.getPosition().getY();\r
- \r
+\r
+ ti.posElem = TerminalUtil.getTerminalPosOnElement(e, ti.t);\r
+ ti.posDia = TerminalUtil.getTerminalPosOnDiagram(e, ti.t);\r
+\r
+ return ti;\r
+ }\r
+\r
+ static class Segment {\r
+ public final ControlPoint begin;\r
+ public final ControlPoint end;\r
+ public Path2D path;\r
+\r
+ public Segment(ControlPoint begin, ControlPoint end) {\r
+ this.begin = begin;\r
+ this.end = end;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return "Segment[begin=" + begin + ", end=" + end + ", path=" + path + "]";\r
+ }\r
+ }\r
+\r
+ private List<Segment> toSegments(Deque<ControlPoint> points) {\r
+ if (points.isEmpty())\r
+ return Collections.emptyList();\r
+\r
+ List<Segment> segments = new ArrayList<Segment>();\r
+\r
+ Iterator<ControlPoint> it = points.iterator();\r
+ ControlPoint prev = it.next();\r
+ while (it.hasNext()) {\r
+ ControlPoint next = it.next();\r
+ segments.add(new Segment(prev, next));\r
+ prev = next;\r
+ }\r
+\r
+ return segments;\r
+ }\r
+\r
+ public interface SysdynConnection extends IConnection { }\r
+\r
+ @Override\r
+ protected void updateSG() {\r
+ if (controlPoints.isEmpty())\r
+ return;\r
+\r
+ // Route connection segments separately\r
+ IRouter2 router = ElementUtils.getHintOrDefault(diagram, DiagramHints.ROUTE_ALGORITHM, TrivialRouter2.INSTANCE);\r
+ final List<Segment> segments = toSegments(controlPoints);\r
+ //System.out.println("controlpoints: " + controlPoints);\r
+ //System.out.println("segments: " + segments);\r
+ router.route(new SysdynConnection() {\r
+ @Override\r
+ public Collection<? extends Object> getSegments() {\r
+ return segments;\r
+ }\r
+\r
+ @Override\r
+ public Connector getBegin(Object seg) {\r
+ return getConnector(((Segment) seg).begin);\r
+ }\r
+\r
+ @Override\r
+ public Connector getEnd(Object seg) {\r
+ return getConnector(((Segment) seg).end);\r
+ }\r
+\r
+ private Connector getConnector(ControlPoint cp) {\r
+ Connector c = new Connector();\r
+ c.x = cp.getPosition().getX();\r
+ c.y = cp.getPosition().getY();\r
+\r
c.allowedDirections = Constants.EAST_FLAG | Constants.WEST_FLAG\r
- | Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
-\r
- TerminalInfo ti = cp.getAttachedTerminal();\r
- if (ti != null && (ti != startFlag && ti != endFlag)) {\r
- if(ti.e.getElementClass().containsClass(ValveSceneGraph.class)) {\r
- Rectangle2D bounds = ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
- c.parentObstacle = new Rectangle2D.Double(\r
- bounds.getCenterX() - FlowRouter.OFFSET,\r
- bounds.getCenterY() - FlowRouter.OFFSET, \r
- FlowRouter.OFFSET * 2,\r
- FlowRouter.OFFSET * 2);\r
- } else {\r
- c.parentObstacle = ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
- }\r
- } else if (ti != null && ti == startFlag) {\r
- c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
- ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D());\r
- } else if (isEndingInFlag() && ti.e != null) {\r
- c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
- CloudFactory.CLOUD_IMAGE.getBounds());\r
- } else {\r
- c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
- BranchPointClass.DEFAULT_IMAGE2.getBounds());\r
- }\r
-\r
- return c;\r
- }\r
-\r
- @Override\r
- public void setPath(Object seg, Path2D path) {\r
- ((Segment) seg).path = (Path2D) path.clone();\r
- }\r
-\r
-// private int toAllowedDirections(BranchPoint.Direction direction) {\r
-// switch (direction) {\r
-// case Any:\r
-// return 0xf;\r
-// case Horizontal:\r
-// return Constants.EAST_FLAG | Constants.WEST_FLAG;\r
-// case Vertical:\r
-// return Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
-// default:\r
-// throw new IllegalArgumentException("unrecognized direction: " + direction);\r
-// }\r
-// }\r
- });\r
-\r
- // Combine the routed paths\r
- Path2D path = new Path2D.Double();\r
- for (Segment seg : segments) {\r
- //System.out.println("SEG: " + seg);\r
- if (seg.path != null)\r
- path.append(seg.path.getPathIterator(null), true);\r
- }\r
- \r
- // Create scene graph to visualize the connection.\r
- ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
- pathNode.setShape(path);\r
- \r
- /*\r
- * Removed Points\r
- */\r
- \r
- setDirty();\r
- }\r
- \r
- \r
- @Override\r
+ | Constants.NORTH_FLAG | Constants.SOUTH_FLAG;\r
+\r
+ TerminalInfo ti = cp.getAttachedTerminal();\r
+ if (ti != null && (ti != startFlag && ti != endFlag)) {\r
+ if(ti.e.getElementClass().containsClass(ValveSceneGraph.class)) {\r
+ Rectangle2D bounds = ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
+ c.parentObstacle = new Rectangle2D.Double(\r
+ bounds.getCenterX() - FlowRouter.OFFSET,\r
+ bounds.getCenterY() - FlowRouter.OFFSET, \r
+ FlowRouter.OFFSET * 2,\r
+ FlowRouter.OFFSET * 2);\r
+ } else {\r
+ c.parentObstacle = ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D();\r
+ }\r
+ } else if (ti != null && ti == startFlag) {\r
+ c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
+ ElementUtils.getElementBoundsOnDiagram(ti.e).getBounds2D());\r
+ } else if (isEndingInFlag() && ti.e != null) {\r
+ c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
+ CloudFactory.CLOUD_IMAGE.getBounds());\r
+ } else {\r
+ c.parentObstacle = org.simantics.scenegraph.utils.GeometryUtils.transformRectangle(AffineTransform.getTranslateInstance(c.x, c.y),\r
+ BranchPointClass.DEFAULT_IMAGE2.getBounds());\r
+ }\r
+\r
+ return c;\r
+ }\r
+\r
+ @Override\r
+ public void setPath(Object seg, Path2D path) {\r
+ ((Segment) seg).path = (Path2D) path.clone();\r
+ }\r
+ });\r
+\r
+ // Combine the routed paths\r
+ Path2D path = new Path2D.Double();\r
+ for (Segment seg : segments) {\r
+ //System.out.println("SEG: " + seg);\r
+ if (seg.path != null)\r
+ path.append(seg.path.getPathIterator(null), true);\r
+ }\r
+\r
+ // Create scene graph to visualize the connection.\r
+ ShapeNode pathNode = ghostNode.getOrCreateNode("path", ShapeNode.class);\r
+ pathNode.setShape(path);\r
+\r
+ /*\r
+ * Removed Points\r
+ */\r
+\r
+ setDirty();\r
+ }\r
+\r
+ @Override\r
protected Object canConnect(final IConnectionAdvisor advisor, final IElement endElement, final Terminal endTerminal) {\r
- final IElement se = startTerminal != null ? startTerminal.e : startFlag.e;\r
- final Terminal st = startTerminal != null ? startTerminal.t : null;\r
+ final IElement se = startTerminal != null ? startTerminal.e : startFlag.e;\r
+ final Terminal st = startTerminal != null ? startTerminal.t : null;\r
\r
if(se.equals(endElement)) return null;\r
if(Boolean.FALSE.equals(diagram.getHint(DiagramHints.KEY_USE_CONNECTION_FLAGS)) && endElement == null) {\r
Resource start = soa.adapt(Resource.class);\r
if(g.isInheritedFrom(start, sr.ModuleSymbol) && !end.equals(sr.InputSymbol)) return null;\r
if(end.equals(sr.StockSymbol)) return null;\r
- if(end.equals(sr.ShadowSymbol)) return null;\r
+ if(end.equals(sr.ShadowSymbol)) return null;\r
} else if (currentConnection.equals(flow)) {\r
if(!(end.equals(sr.StockSymbol) || end.equals(sr.ValveSymbol) || end.equals(sr.CloudSymbol))) return null;\r
} else {\r
}\r
\r
}\r
- \r
- protected boolean processMouseMove(MouseMovedEvent me) {\r
- mouseHasMoved = true;\r
\r
- Point2D mouseControlPos = me.controlPosition;\r
- Point2D mouseCanvasPos = util.controlToCanvas(mouseControlPos, new Point2D.Double());\r
+ @Override\r
+ protected boolean processMouseMove(MouseMovedEvent me) {\r
+ mouseHasMoved = true;\r
\r
- ISnapAdvisor snapAdvisor = getHint(DiagramHints.SNAP_ADVISOR);\r
- if (snapAdvisor != null)\r
- snapAdvisor.snap(mouseCanvasPos);\r
+ Point2D mouseControlPos = me.controlPosition;\r
+ Point2D mouseCanvasPos = util.controlToCanvas(mouseControlPos, new Point2D.Double());\r
\r
- // Record last snapped canvas position of mouse.\r
- this.lastMouseCanvasPos.setLocation(mouseCanvasPos);\r
+ ISnapAdvisor snapAdvisor = getHint(DiagramHints.SNAP_ADVISOR);\r
+ if (snapAdvisor != null)\r
+ snapAdvisor.snap(mouseCanvasPos);\r
\r
- if (isEndingInFlag()) {\r
- endFlagNode.setTransform(AffineTransform.getTranslateInstance(mouseCanvasPos.getX(), mouseCanvasPos.getY()));\r
- }\r
+ // Record last snapped canvas position of mouse.\r
+ this.lastMouseCanvasPos.setLocation(mouseCanvasPos);\r
\r
- List<TerminalInfo> tiList = ((org.simantics.sysdyn.ui.editor.participant.SysdynPointerInteractor)pi).pickTerminals(me.controlPosition);\r
+ if (isEndingInFlag()) {\r
+ endFlagNode.setTransform(AffineTransform.getTranslateInstance(mouseCanvasPos.getX(), mouseCanvasPos.getY()));\r
+ }\r
+\r
+ List<TerminalInfo> tiList = ((SysdynPointerInteractor)pi).pickTerminals(me.controlPosition);\r
TerminalInfo ti = null;\r
\r
IConnectionAdvisor advisor = diagram.getHint(DiagramHints.CONNECTION_ADVISOR);\r
break;\r
}\r
}\r
- \r
- if (ti != null && !isStartTerminal(ti.e, ti.t)) {\r
- Pair<ConnectionJudgement, TerminalInfo> canConnect = canConnect(ti.e, ti.t);\r
- if (canConnect != null) {\r
- connectionJudgment = canConnect.first;\r
-\r
- if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) {\r
- controlPoints.getLast()\r
- .setPosition(ti.posDia)\r
- .setAttachedToTerminal(ti);\r
-\r
- endTerminal = ti;\r
- }\r
-\r
- // Make sure that we are ending with a flag if ALT is pressed\r
- // and no end terminal is defined.\r
- endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
-\r
- updateSG();\r
- return false;\r
- }\r
- }\r
-\r
- connectionJudgment = null;\r
- if (isEndTerminalDefined()) {\r
- // CASE: Mouse was previously on top of a valid terminal to end\r
- // the connection. Now the mouse has been moved where there is\r
- // no longer a terminal to connect to.\r
- //\r
- // => Disconnect the last edge segment from the previous\r
- // terminal, mark endElement/endTerminal non-existent\r
- // and connect the disconnected edge to a new branch point.\r
-\r
- controlPoints.getLast()\r
- .setPosition(mouseCanvasPos)\r
- .setDirection(calculateCurrentBranchPointDirection())\r
- .setAttachedToTerminal(null);\r
-\r
- endTerminal = null;\r
- } else {\r
- // CASE: Mouse was not previously on top of a valid ending\r
- // element terminal.\r
- //\r
- // => Move and re-orient last branch point.\r
-\r
- controlPoints.getLast()\r
- .setPosition(mouseCanvasPos)\r
- .setDirection(calculateCurrentBranchPointDirection());\r
- }\r
-\r
- // Make sure that we are ending with a flag if ALT is pressed and no end\r
- // terminal is defined.\r
- endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
-\r
- updateSG();\r
-\r
- return false;\r
- }\r
-\r
- @Override\r
+\r
+ if (ti != null && !isStartTerminal(ti.e, ti.t)) {\r
+ Pair<ConnectionJudgement, TerminalInfo> canConnect = canConnect(ti.e, ti.t);\r
+ if (canConnect != null) {\r
+ connectionJudgment = canConnect.first;\r
+\r
+ if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) {\r
+ controlPoints.getLast()\r
+ .setPosition(ti.posDia)\r
+ .setAttachedToTerminal(ti);\r
+\r
+ endTerminal = ti;\r
+ }\r
+\r
+ // Make sure that we are ending with a flag if ALT is pressed\r
+ // and no end terminal is defined. If we are in flow creation\r
+ // mode, we want to show the terminal cloud (or flag) even when\r
+ // alt is not pressed.\r
+ if (inFlowMode() && flowInProgress() && !startTerminals.isEmpty())\r
+ endWithoutTerminal(lastMouseCanvasPos, true);\r
+ else\r
+ endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
+ updateSG();\r
+ return false;\r
+ }\r
+ }\r
+\r
+ connectionJudgment = null;\r
+ if (isEndTerminalDefined()) {\r
+ // CASE: Mouse was previously on top of a valid terminal to end\r
+ // the connection. Now the mouse has been moved where there is\r
+ // no longer a terminal to connect to.\r
+ //\r
+ // => Disconnect the last edge segment from the previous\r
+ // terminal, mark endElement/endTerminal non-existent\r
+ // and connect the disconnected edge to a new branch point.\r
+\r
+ controlPoints.getLast()\r
+ .setPosition(mouseCanvasPos)\r
+ .setDirection(calculateCurrentBranchPointDirection())\r
+ .setAttachedToTerminal(null);\r
+\r
+ endTerminal = null;\r
+ } else {\r
+ // CASE: Mouse was not previously on top of a valid ending\r
+ // element terminal.\r
+ //\r
+ // => Move and re-orient last branch point.\r
+\r
+ controlPoints.getLast()\r
+ .setPosition(mouseCanvasPos)\r
+ .setDirection(calculateCurrentBranchPointDirection());\r
+ }\r
+\r
+ // Make sure that we are ending with a flag if ALT is pressed and no end\r
+ // terminal is defined. If we are in flow creation mode, we want to show \r
+ // the terminal cloud (or flag) even when alt is not pressed.\r
+ if (inFlowMode() && flowInProgress() && !startTerminals.isEmpty())\r
+ endWithoutTerminal(lastMouseCanvasPos, true);\r
+ else\r
+ endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));\r
+ updateSG();\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ protected boolean processMouseButtonPress(MouseButtonPressedEvent e) {\r
+ MouseButtonEvent me = e;\r
+\r
+ // Do nothing before the mouse has moved at least a little.\r
+ // This prevents the user from ending the connection right where\r
+ // it started.\r
+ if (!mouseHasMoved)\r
+ return true;\r
+\r
+ if (me.button == MouseEvent.LEFT_BUTTON || \r
+ (me.button == MouseEvent.RIGHT_BUTTON && flowInProgress() && !inFlowMode())) {\r
+ Point2D mouseControlPos = me.controlPosition;\r
+ Point2D mouseCanvasPos = util.getInverseTransform().transform(mouseControlPos, new Point2D.Double());\r
+\r
+ ISnapAdvisor snapAdvisor = getHint(DiagramHints.SNAP_ADVISOR);\r
+ if (snapAdvisor != null)\r
+ snapAdvisor.snap(mouseCanvasPos);\r
+\r
+ // Clicked on an allowed end terminal. End connection & end mode.\r
+ if (isEndTerminalDefined()) {\r
+ createConnection();\r
+ remove();\r
+ return true;\r
+ } else {\r
+ // Finish connection in thin air only if the\r
+ // connection was started from a valid terminal.\r
+ \r
+ // If we are in flow creation mode, we want to be able to\r
+ // create the terminal cloud (or flag) without having to \r
+ // press alt.\r
+ \r
+ if (!startTerminals.isEmpty() && ((me.stateMask & MouseEvent.ALT_MASK) != 0 || \r
+ (inFlowMode() && flowInProgress()))) {\r
+ Pair<ConnectionJudgement, TerminalInfo> pair = canConnect(null, null);\r
+ if (pair != null) {\r
+ connectionJudgment = (ConnectionJudgement) pair.first;\r
+ selectedStartTerminal = pair.second;\r
+ createConnection();\r
+ setDirty();\r
+ remove();\r
+ } else {\r
+ // Inform the user why connection couldn't be created.\r
+ ErrorLogger.defaultLogWarning("Can't resolve connection type for new connection.", null);\r
+ }\r
+ return true;\r
+ } else if (routePointsAllowed()\r
+ && (me.stateMask & (MouseEvent.ALT_MASK | MouseEvent.SHIFT_MASK | MouseEvent.CTRL_MASK)) == 0) {\r
+ // Add new connection control point.\r
+ controlPoints.add(newControlPointWithCalculatedDirection(mouseCanvasPos));\r
+ resetForcedBranchPointDirection();\r
+ updateSG();\r
+ }\r
+ }\r
+ }\r
+\r
+ return true;\r
+ }\r
+ \r
+ private boolean inFlowMode() {\r
+ return SysdynElementHints.FLOW_TOOL.equals(getHint(SysdynElementHints.SYSDYN_KEY_TOOL));\r
+ }\r
+ \r
+ private boolean flowInProgress() {\r
+ return elementClassProvider.get(ElementClasses.CONNECTION).equals(elementClassProvider.get(ConnectionClasses.FLOW));\r
+ }\r
+\r
+ @Override\r
protected void createConnection() {\r
- \r
- if(this.connectionJudgment == null) return;\r
- \r
- final ConnectionJudgement judgment = this.connectionJudgment;\r
- // ConnectionBuilder changed to SysdynconnectionBuilder to support overlapping terminals and valve creation\r
- final ConnectionBuilder builder = new SysdynConnectionBuilder(this.diagram);\r
- final Deque<ControlPoint> controlPoints = this.controlPoints;\r
- final TerminalInfo startTerminal = this.startTerminal;\r
- final TerminalInfo endTerminal = this.endTerminal;\r
-\r
- SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- builder.create(graph, judgment, controlPoints, startTerminal, endTerminal);\r
- }\r
- }, new Callback<DatabaseException>() {\r
- @Override\r
- public void run(DatabaseException parameter) {\r
- if (parameter != null)\r
- ExceptionUtils.logAndShowError(parameter);\r
- }\r
- });\r
- } \r
+\r
+ if(this.connectionJudgment == null) return;\r
+\r
+ final ConnectionJudgement judgment = this.connectionJudgment;\r
+ // ConnectionBuilder changed to SysdynconnectionBuilder to support overlapping terminals and valve creation\r
+ final ConnectionBuilder builder = new SysdynConnectionBuilder(this.diagram);\r
+ final Deque<ControlPoint> controlPoints = this.controlPoints;\r
+ final TerminalInfo startTerminal = this.startTerminal;\r
+ final TerminalInfo endTerminal = this.endTerminal;\r
+\r
+ SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+ builder.create(graph, judgment, controlPoints, startTerminal, endTerminal);\r
+ }\r
+ }, new Callback<DatabaseException>() {\r
+ @Override\r
+ public void run(DatabaseException parameter) {\r
+ if (parameter != null)\r
+ ExceptionUtils.logAndShowError(parameter);\r
+ }\r
+ });\r
+ } \r
}\r