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%2Fhandler%2FConnectionCommandHandler.java;h=ec2bc6a6f185e660107544f57cd439160d434e80;hp=129cdf16d431055d1189eea6d907b2063c7300e4;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionCommandHandler.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionCommandHandler.java index 129cdf16d..ec2bc6a6f 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionCommandHandler.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionCommandHandler.java @@ -1,311 +1,311 @@ -/******************************************************************************* - * 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: - * - * - * 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 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 routePoints = getBranchPoints(Integer.MAX_VALUE); - if (routePoints.isEmpty()) - return false; - - // Rotate branch points. - try { - SimanticsUI.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 { - 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); - 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 getBranchPoints(int maxDegree) throws DatabaseException { - - Set ss = selection.getSelection(0); - if (ss.isEmpty()) - return Collections.emptySet(); - - final Set result = new HashSet(); - Collection connections = new ArrayList(); - 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 null. - */ - IElement getSingleConnectionSegment() { - Set 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 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 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; - } - -} +/******************************************************************************* + * 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: + *
    + *
  • DELETE for deleting route points from DIA.Connection type connections + *
  • SPLIT_CONNECTION for creating new route points into DIA.Connection type connections + *
  • ROTATE_ELEMENT_CW & ROTATE_ELEMENT_CCW for rotating route points orientations. + *
+ * + * 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 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 routePoints = getBranchPoints(Integer.MAX_VALUE); + if (routePoints.isEmpty()) + return false; + + // Rotate branch points. + try { + SimanticsUI.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 { + 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); + 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 getBranchPoints(int maxDegree) throws DatabaseException { + + Set ss = selection.getSelection(0); + if (ss.isEmpty()) + return Collections.emptySet(); + + final Set result = new HashSet(); + Collection connections = new ArrayList(); + 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 null. + */ + IElement getSingleConnectionSegment() { + Set 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 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 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; + } + +}