-/*******************************************************************************\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.handler;\r
-\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.HashSet;\r
-import java.util.Set;\r
-\r
-import org.simantics.Simantics;\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.synchronization.graph.RemoveBranchpoint;\r
-import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
-import org.simantics.g2d.connection.ConnectionEntity;\r
-import org.simantics.g2d.diagram.DiagramHints;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.handler.PickRequest;\r
-import org.simantics.g2d.diagram.handler.Topology;\r
-import org.simantics.g2d.diagram.handler.Topology.Connection;\r
-import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
-import org.simantics.g2d.diagram.participant.Selection;\r
-import org.simantics.g2d.element.ElementHints;\r
-import org.simantics.g2d.element.ElementUtils;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.elementclass.BranchPoint;\r
-import org.simantics.g2d.elementclass.BranchPoint.Direction;\r
-import org.simantics.g2d.participant.MouseUtil;\r
-import org.simantics.g2d.participant.MouseUtil.MouseInfo;\r
-import org.simantics.g2d.participant.WorkbenchStatusLine;\r
-import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
-import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
-import org.simantics.scenegraph.g2d.events.command.Commands;\r
-import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-/**\r
- * A participant for handling:\r
- * <ul>\r
- * <li>DELETE for deleting route points from DIA.Connection type connections\r
- * <li>SPLIT_CONNECTION for creating new route points into DIA.Connection type connections\r
- * <li>ROTATE_ELEMENT_CW & ROTATE_ELEMENT_CCW for rotating route points orientations.\r
- * </ul>\r
- * \r
- * NOTE: this participant does nothing useful with DIA.RouteGraphConnection type connections.\r
- * \r
- * @author Tuukka Lehtonen\r
- * \r
- * TODO: start using {@link WorkbenchStatusLine}\r
- */\r
-public class ConnectionCommandHandler extends AbstractDiagramParticipant {\r
-\r
- @Dependency MouseUtil mouseUtil;\r
- @Dependency Selection selection;\r
- //@Dependency WorkbenchStatusLine statusLine;\r
-\r
- @EventHandler(priority = 100)\r
- public boolean handleCommand(CommandEvent event) {\r
- if (Commands.DELETE.equals(event.command)) {\r
- try {\r
- return joinConnection();\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- return false;\r
- }\r
- } else if (Commands.SPLIT_CONNECTION.equals(event.command) && routePointsEnabled()) {\r
- return splitConnection();\r
- } else if (Commands.ROTATE_ELEMENT_CW.equals(event.command) || Commands.ROTATE_ELEMENT_CCW.equals(event.command)) {\r
- boolean clockWise = Commands.ROTATE_ELEMENT_CW.equals(event.command);\r
- try {\r
- return rotateBranchPoint(clockWise);\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- return false;\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- private boolean routePointsEnabled() {\r
- return Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS));\r
- }\r
-\r
- boolean joinConnection() throws DatabaseException {\r
-\r
- final Set<IElement> routePoints = getBranchPoints(2);\r
-\r
- if (routePoints.isEmpty())\r
- return false;\r
-\r
- selection.clear(0);\r
-\r
- Simantics.getSession().sync(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- for (IElement routePoint : routePoints) {\r
- Object node = ElementUtils.getObject(routePoint);\r
- if (node instanceof Resource) {\r
- new RemoveBranchpoint(routePoint).perform(graph);\r
- }\r
- }\r
- }\r
- });\r
- setDirty();\r
-\r
- //statusLine.message("Deleted " + routePoints.size() + " route points");\r
- return true;\r
- }\r
-\r
- private boolean rotateBranchPoint(final boolean clockWise) throws DatabaseException {\r
- final Set<IElement> routePoints = getBranchPoints(Integer.MAX_VALUE);\r
- if (routePoints.isEmpty())\r
- return false;\r
-\r
- // Rotate branch points.\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
- for (IElement bp : routePoints) {\r
- Resource bpr = (Resource) ElementUtils.getObject(bp);\r
- boolean vertical = graph.hasStatement(bpr, DIA.Vertical, bpr);\r
- boolean horizontal = graph.hasStatement(bpr, DIA.Horizontal, bpr);\r
- Direction dir = Direction.toDirection(horizontal, vertical);\r
- Direction newDir = clockWise ? dir.cycleNext() : dir.cyclePrevious();\r
- switch (newDir) {\r
- case Any:\r
- graph.deny(bpr, DIA.Vertical);\r
- graph.deny(bpr, DIA.Horizontal);\r
- break;\r
- case Horizontal:\r
- graph.deny(bpr, DIA.Vertical);\r
- graph.claim(bpr, DIA.Horizontal, bpr);\r
- break;\r
- case Vertical:\r
- graph.deny(bpr, DIA.Horizontal);\r
- graph.claim(bpr, DIA.Vertical, bpr);\r
- break;\r
- }\r
- }\r
- }\r
- });\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- }\r
-\r
- return true;\r
- }\r
-\r
- boolean splitConnection() {\r
-\r
- final IElement edge = getSingleConnectionSegment();\r
- if (edge == null)\r
- return false;\r
- final IDiagram diagram = ElementUtils.peekDiagram(edge);\r
- if (diagram == null)\r
- return false;\r
-\r
- MouseInfo mi = mouseUtil.getMouseInfo(0);\r
- final Point2D mousePos = mi.canvasPosition;\r
-\r
- ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);\r
- if (snap != null)\r
- snap.snap(mousePos);\r
-\r
- final AffineTransform splitPos = AffineTransform.getTranslateInstance(mousePos.getX(), mousePos.getY());\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
- EdgeResource segment = (EdgeResource) ElementUtils.getObject(edge);\r
- Resource bp = cu.split(segment, splitPos);\r
-\r
- Line2D nearestLine = ConnectionUtil.resolveNearestEdgeLineSegment(mousePos, 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
- });\r
-\r
- selection.clear(0);\r
-\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- }\r
-\r
- return false;\r
- }\r
-\r
- /**\r
- * @return all route points in the current diagram selection if and only if\r
- * only route points are selected. If anything else is selected,\r
- * even branch points, an empty set will be returned.\r
- */\r
- Set<IElement> getBranchPoints(int maxDegree) throws DatabaseException {\r
-\r
- Set<IElement> ss = selection.getSelection(0);\r
- if (ss.isEmpty())\r
- return Collections.emptySet();\r
-\r
- final Set<IElement> result = new HashSet<IElement>();\r
- Collection<Connection> connections = new ArrayList<Connection>();\r
- for (IElement e : ss) {\r
- if (!e.getElementClass().containsClass(BranchPoint.class))\r
- return Collections.emptySet();\r
- ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
- if (ce == null)\r
- return Collections.emptySet();\r
- IDiagram diagram = ElementUtils.peekDiagram(e);\r
- if (diagram == null)\r
- return Collections.emptySet();\r
- for (Topology topology : diagram.getDiagramClass().getItemsByClass(Topology.class)) {\r
- connections.clear();\r
- topology.getConnections(e, ElementUtils.getSingleTerminal(e), connections);\r
- int degree = connections.size();\r
- if (degree < 2 || degree > maxDegree)\r
- return Collections.emptySet();\r
- result.add(e);\r
- }\r
- }\r
-\r
- return result;\r
- }\r
-\r
- /**\r
- * @return if a single edge is selected, return the edge. If a single\r
- * connection is selected and it contains only one edge segment,\r
- * return it. Otherwise return <code>null</code>.\r
- */\r
- IElement getSingleConnectionSegment() {\r
- Set<IElement> s = selection.getSelection(0);\r
- if (s.size() != 1)\r
- return null;\r
- IElement e = s.iterator().next();\r
- if (PickRequest.PickFilter.FILTER_CONNECTIONS.accept(e)) {\r
- // Does this connection have only one edge and no branch points?\r
- ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
- Collection<IElement> coll = ce.getBranchPoints(null);\r
- if (!coll.isEmpty())\r
- return null;\r
- ce.getSegments(coll);\r
- if (coll.size() != 1)\r
- return null;\r
- // Return the only edge element of the whole connection.\r
- return coll.iterator().next();\r
- }\r
- if (PickRequest.PickFilter.FILTER_CONNECTION_EDGES.accept(e))\r
- return e;\r
- return null;\r
- }\r
-\r
- /**\r
- * @return the selected top-level connection element if and only if the\r
- * selection contains the connection or parts of the same connection\r
- * (edge segments or branch/route points) and nothing else.\r
- */\r
- IElement getSingleConnection() {\r
-\r
- Set<IElement> ss = selection.getSelection(0);\r
- if (ss.isEmpty())\r
- return null;\r
-\r
- IElement result = null;\r
-\r
- for (IElement e : ss) {\r
- ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);\r
- if (ce == null)\r
- continue;\r
- if (result != null && !ce.getConnection().equals(result))\r
- return null;\r
- result = ce.getConnection();\r
- }\r
-\r
- return result;\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.handler;
+
+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.HashSet;
+import java.util.Set;
+
+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.synchronization.graph.RemoveBranchpoint;
+import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
+import org.simantics.g2d.connection.ConnectionEntity;
+import org.simantics.g2d.diagram.DiagramHints;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.PickRequest;
+import org.simantics.g2d.diagram.handler.Topology;
+import org.simantics.g2d.diagram.handler.Topology.Connection;
+import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
+import org.simantics.g2d.diagram.participant.Selection;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.elementclass.BranchPoint;
+import org.simantics.g2d.elementclass.BranchPoint.Direction;
+import org.simantics.g2d.participant.MouseUtil;
+import org.simantics.g2d.participant.MouseUtil.MouseInfo;
+import org.simantics.g2d.participant.WorkbenchStatusLine;
+import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
+import org.simantics.scenegraph.g2d.events.command.CommandEvent;
+import org.simantics.scenegraph.g2d.events.command.Commands;
+import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
+import org.simantics.ui.SimanticsUI;
+import org.simantics.utils.ui.ErrorLogger;
+
+/**
+ * A participant for handling:
+ * <ul>
+ * <li>DELETE for deleting route points from DIA.Connection type connections
+ * <li>SPLIT_CONNECTION for creating new route points into DIA.Connection type connections
+ * <li>ROTATE_ELEMENT_CW & ROTATE_ELEMENT_CCW for rotating route points orientations.
+ * </ul>
+ *
+ * NOTE: this participant does nothing useful with DIA.RouteGraphConnection type connections.
+ *
+ * @author Tuukka Lehtonen
+ *
+ * TODO: start using {@link WorkbenchStatusLine}
+ */
+public class ConnectionCommandHandler extends AbstractDiagramParticipant {
+
+ @Dependency MouseUtil mouseUtil;
+ @Dependency Selection selection;
+ //@Dependency WorkbenchStatusLine statusLine;
+
+ @EventHandler(priority = 100)
+ public boolean handleCommand(CommandEvent event) {
+ if (Commands.DELETE.equals(event.command)) {
+ try {
+ return joinConnection();
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ return false;
+ }
+ } else if (Commands.SPLIT_CONNECTION.equals(event.command) && routePointsEnabled()) {
+ return splitConnection();
+ } else if (Commands.ROTATE_ELEMENT_CW.equals(event.command) || Commands.ROTATE_ELEMENT_CCW.equals(event.command)) {
+ boolean clockWise = Commands.ROTATE_ELEMENT_CW.equals(event.command);
+ try {
+ return rotateBranchPoint(clockWise);
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ return false;
+ }
+ }
+ return false;
+ }
+
+ private boolean routePointsEnabled() {
+ return Boolean.TRUE.equals(diagram.getHint(DiagramHints.KEY_ALLOW_ROUTE_POINTS));
+ }
+
+ boolean joinConnection() throws DatabaseException {
+
+ final Set<IElement> routePoints = getBranchPoints(2);
+
+ if (routePoints.isEmpty())
+ return false;
+
+ selection.clear(0);
+
+ Simantics.getSession().sync(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ for (IElement routePoint : routePoints) {
+ Object node = ElementUtils.getObject(routePoint);
+ if (node instanceof Resource) {
+ new RemoveBranchpoint(routePoint).perform(graph);
+ }
+ }
+ }
+ });
+ setDirty();
+
+ //statusLine.message("Deleted " + routePoints.size() + " route points");
+ return true;
+ }
+
+ private boolean rotateBranchPoint(final boolean clockWise) throws DatabaseException {
+ final Set<IElement> routePoints = getBranchPoints(Integer.MAX_VALUE);
+ if (routePoints.isEmpty())
+ return false;
+
+ // Rotate branch points.
+ try {
+ Simantics.getSession().syncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+ for (IElement bp : routePoints) {
+ Resource bpr = (Resource) ElementUtils.getObject(bp);
+ boolean vertical = graph.hasStatement(bpr, DIA.Vertical, bpr);
+ boolean horizontal = graph.hasStatement(bpr, DIA.Horizontal, bpr);
+ Direction dir = Direction.toDirection(horizontal, vertical);
+ Direction newDir = clockWise ? dir.cycleNext() : dir.cyclePrevious();
+ switch (newDir) {
+ case Any:
+ graph.deny(bpr, DIA.Vertical);
+ graph.deny(bpr, DIA.Horizontal);
+ break;
+ case Horizontal:
+ graph.deny(bpr, DIA.Vertical);
+ graph.claim(bpr, DIA.Horizontal, bpr);
+ break;
+ case Vertical:
+ graph.deny(bpr, DIA.Horizontal);
+ graph.claim(bpr, DIA.Vertical, bpr);
+ break;
+ }
+ }
+ }
+ });
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+
+ return true;
+ }
+
+ boolean splitConnection() {
+
+ final IElement edge = getSingleConnectionSegment();
+ if (edge == null)
+ return false;
+ final IDiagram diagram = ElementUtils.peekDiagram(edge);
+ if (diagram == null)
+ return false;
+
+ MouseInfo mi = mouseUtil.getMouseInfo(0);
+ final Point2D mousePos = mi.canvasPosition;
+
+ ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);
+ if (snap != null)
+ snap.snap(mousePos);
+
+ final AffineTransform splitPos = AffineTransform.getTranslateInstance(mousePos.getX(), mousePos.getY());
+
+ 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);
+ EdgeResource segment = (EdgeResource) ElementUtils.getObject(edge);
+ Resource bp = cu.split(segment, splitPos);
+
+ Line2D nearestLine = ConnectionUtil.resolveNearestEdgeLineSegment(mousePos, 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);
+ }
+ }
+ }
+ });
+
+ selection.clear(0);
+
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return all route points in the current diagram selection if and only if
+ * only route points are selected. If anything else is selected,
+ * even branch points, an empty set will be returned.
+ */
+ Set<IElement> getBranchPoints(int maxDegree) throws DatabaseException {
+
+ Set<IElement> ss = selection.getSelection(0);
+ if (ss.isEmpty())
+ return Collections.emptySet();
+
+ final Set<IElement> result = new HashSet<IElement>();
+ Collection<Connection> connections = new ArrayList<Connection>();
+ for (IElement e : ss) {
+ if (!e.getElementClass().containsClass(BranchPoint.class))
+ return Collections.emptySet();
+ ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+ if (ce == null)
+ return Collections.emptySet();
+ IDiagram diagram = ElementUtils.peekDiagram(e);
+ if (diagram == null)
+ return Collections.emptySet();
+ for (Topology topology : diagram.getDiagramClass().getItemsByClass(Topology.class)) {
+ connections.clear();
+ topology.getConnections(e, ElementUtils.getSingleTerminal(e), connections);
+ int degree = connections.size();
+ if (degree < 2 || degree > maxDegree)
+ return Collections.emptySet();
+ result.add(e);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @return if a single edge is selected, return the edge. If a single
+ * connection is selected and it contains only one edge segment,
+ * return it. Otherwise return <code>null</code>.
+ */
+ IElement getSingleConnectionSegment() {
+ Set<IElement> s = selection.getSelection(0);
+ if (s.size() != 1)
+ return null;
+ IElement e = s.iterator().next();
+ if (PickRequest.PickFilter.FILTER_CONNECTIONS.accept(e)) {
+ // Does this connection have only one edge and no branch points?
+ ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+ Collection<IElement> coll = ce.getBranchPoints(null);
+ if (!coll.isEmpty())
+ return null;
+ ce.getSegments(coll);
+ if (coll.size() != 1)
+ return null;
+ // Return the only edge element of the whole connection.
+ return coll.iterator().next();
+ }
+ if (PickRequest.PickFilter.FILTER_CONNECTION_EDGES.accept(e))
+ return e;
+ return null;
+ }
+
+ /**
+ * @return the selected top-level connection element if and only if the
+ * selection contains the connection or parts of the same connection
+ * (edge segments or branch/route points) and nothing else.
+ */
+ IElement getSingleConnection() {
+
+ Set<IElement> ss = selection.getSelection(0);
+ if (ss.isEmpty())
+ return null;
+
+ IElement result = null;
+
+ for (IElement e : ss) {
+ ConnectionEntity ce = e.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+ if (ce == null)
+ continue;
+ if (result != null && !ce.getConnection().equals(result))
+ return null;
+ result = ce.getConnection();
+ }
+
+ return result;
+ }
+
+}