/***************************************************************************** * Copyright (c) 2010 CEA * * * 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: * Atos Origin - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.sequence.edit.policies; import java.util.Collections; import java.util.List; import org.eclipse.draw2d.AbstractRouter; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.ConnectionRouter; import org.eclipse.draw2d.FigureCanvas; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.EditPart; import org.eclipse.gef.Request; import org.eclipse.gef.RequestConstants; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gef.commands.UnexecutableCommand; import org.eclipse.gef.requests.BendpointRequest; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gef.requests.ReconnectRequest; import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand; import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart; import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ConnectionBendpointEditPolicy; import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; import org.eclipse.gmf.runtime.diagram.ui.util.SelectInDiagramHelper; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure; import org.eclipse.gmf.runtime.gef.ui.internal.editpolicies.LineMode; import org.eclipse.papyrus.uml.diagram.sequence.draw2d.routers.MessageRouter.RouterKind; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message2EditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message4EditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message4EditPart.MessageCreate; import org.eclipse.papyrus.uml.diagram.sequence.part.Messages; import org.eclipse.papyrus.uml.diagram.sequence.util.LifelineMessageCreateHelper; import org.eclipse.papyrus.uml.diagram.sequence.util.OccurrenceSpecificationMoveHelper; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceRequestConstant; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil; import org.eclipse.uml2.uml.Message; import org.eclipse.uml2.uml.MessageEnd; import org.eclipse.uml2.uml.OccurrenceSpecification; /** * This bendpoint edit policy is used to allow drag of horizontal messages and forbid drag otherwise. * * @author mvelten * */ @SuppressWarnings("restriction") public class MessageConnectionLineSegEditPolicy extends ConnectionBendpointEditPolicy { public MessageConnectionLineSegEditPolicy() { super(LineMode.ORTHOGONAL_FREE); } @Override public Command getCommand(Request request) { RouterKind kind = RouterKind.getKind(getConnection(), getConnection().getPoints()); if(kind == RouterKind.SELF || kind == RouterKind.HORIZONTAL || getConnection() instanceof MessageCreate){ return super.getCommand(request); } return null; } /** * Move the anchors along with the line and update bendpoints accordingly. */ @Override protected Command getBendpointsChangedCommand(BendpointRequest request) { if((getHost().getViewer() instanceof ScrollingGraphicalViewer) && (getHost().getViewer().getControl() instanceof FigureCanvas)) { SelectInDiagramHelper.exposeLocation((FigureCanvas)getHost().getViewer().getControl(), request.getLocation().getCopy()); } if(getHost() instanceof ConnectionNodeEditPart) { ConnectionNodeEditPart connectionPart = (ConnectionNodeEditPart)getHost(); EObject message = connectionPart.resolveSemanticElement(); if(message instanceof Message) { MessageEnd send = ((Message)message).getSendEvent(); MessageEnd rcv = ((Message)message).getReceiveEvent(); EditPart srcPart = connectionPart.getSource(); LifelineEditPart srcLifelinePart = SequenceUtil.getParentLifelinePart(srcPart); EditPart tgtPart = connectionPart.getTarget(); LifelineEditPart tgtLifelinePart = SequenceUtil.getParentLifelinePart(tgtPart); if(send instanceof OccurrenceSpecification && rcv instanceof OccurrenceSpecification && srcLifelinePart != null && tgtLifelinePart != null) { RouterKind kind = RouterKind.getKind(getConnection(), getConnection().getPoints()); if(getHost() instanceof Message2EditPart && kind == RouterKind.SELF){ return getSelfLinkMoveCommand(request, connectionPart, send, rcv, srcLifelinePart); }else if(getHost() instanceof Message4EditPart){ IFigure fig = tgtLifelinePart.getPrimaryShape().getFigureLifelineNameContainerFigure(); Rectangle bounds = fig.getBounds().getCopy(); fig.translateToAbsolute(bounds); PointList points = getConnection().getPoints(); Point sourceRefPoint = points.getFirstPoint().getCopy();; getConnection().translateToAbsolute(sourceRefPoint); int dy = sourceRefPoint.y - bounds.getCenter().y; Point location = tgtLifelinePart.getFigure().getBounds().getLocation().getCopy().translate(0, dy); Command moveCmd = new ICommandProxy(new SetBoundsCommand(tgtLifelinePart.getEditingDomain(), DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter(tgtLifelinePart.getNotationView()), location)); // Take care of the order of commands, to make sure target is always bellow the source. if(dy < 0){ // move up return LifelineMessageCreateHelper.moveCascadeLifeline(tgtLifelinePart,moveCmd,dy); }else{ // move down Command cmd = LifelineMessageCreateHelper.moveCascadeLifeline(tgtLifelinePart,null,dy); cmd = cmd == null? moveCmd: cmd.chain(moveCmd); return cmd; } }else{ int y = request.getLocation().y; List<EditPart> empty = Collections.emptyList(); Command srcCmd = OccurrenceSpecificationMoveHelper.getMoveOccurrenceSpecificationsCommand((OccurrenceSpecification)send, null, y, -1, srcLifelinePart, empty); Command tgtCmd = OccurrenceSpecificationMoveHelper.getMoveOccurrenceSpecificationsCommand((OccurrenceSpecification)rcv, null, y, -1, tgtLifelinePart, empty); CompoundCommand compoudCmd = new CompoundCommand(Messages.MoveMessageCommand_Label); /* * Take care of the order of commands, to make sure target is always bellow the source. * Otherwise, moving the target above the source would cause order conflict with existing CF. */ Point oldLocation = SequenceUtil.getAbsoluteEdgeExtremity(connectionPart, true); if(oldLocation != null) { int oldY = oldLocation.y; if(oldY < y) { compoudCmd.add(tgtCmd); compoudCmd.add(srcCmd); } else { compoudCmd.add(srcCmd); compoudCmd.add(tgtCmd); } return compoudCmd; } } } } } return UnexecutableCommand.INSTANCE; } protected Command getSelfLinkMoveCommand(BendpointRequest request, ConnectionNodeEditPart connectionPart, MessageEnd send, MessageEnd rcv, LifelineEditPart srcLifelinePart) { CompoundCommand compoudCmd = new CompoundCommand(Messages.MoveMessageCommand_Label); PointList points = getConnection().getPoints(); Point sourceRefPoint = points.getFirstPoint();; Point targetRefPoint = points.getLastPoint();; getConnection().translateToAbsolute(sourceRefPoint); getConnection().translateToAbsolute(targetRefPoint); Point oldSourcePoint = SequenceUtil.findLocationOfEvent(srcLifelinePart, (OccurrenceSpecification)send); int dy = sourceRefPoint.y - oldSourcePoint.y; int dx = request.getLocation().x > sourceRefPoint.x ? 3 : -3; // check bounds NodeFigure fig = srcLifelinePart.getPrimaryShape().getFigureLifelineDotLineFigure().getDashLineRectangle(); Rectangle bounds = fig.getBounds().getCopy(); fig.translateToAbsolute(bounds); bounds.expand(6, 0); if(!bounds.contains(sourceRefPoint) || !bounds.contains(targetRefPoint)){ return UnexecutableCommand.INSTANCE; // cannot move outside lifeline part } sourceRefPoint = sourceRefPoint.translate(dx, 0); targetRefPoint = targetRefPoint.translate(dx, 0); Command srcCmd = getReconnectCommand(connectionPart, srcLifelinePart, sourceRefPoint, RequestConstants.REQ_RECONNECT_SOURCE); Command tgtCmd = getReconnectCommand(connectionPart, srcLifelinePart, targetRefPoint, RequestConstants.REQ_RECONNECT_TARGET); if(dy < 0){ // move up compoudCmd.add(srcCmd); compoudCmd.add(tgtCmd); }else{ // move down compoudCmd.add(tgtCmd); compoudCmd.add(srcCmd); } return compoudCmd; } protected Command getReconnectCommand(ConnectionNodeEditPart connectionPart, LifelineEditPart targetPart, Point location, String requestType) { // Create and set the properties of the request ReconnectRequest reconnReq = new ReconnectRequest(); reconnReq.setConnectionEditPart(connectionPart); reconnReq.setLocation(location); reconnReq.setTargetEditPart(targetPart); reconnReq.setType(requestType); // add a parameter to bypass the move impact to avoid infinite loop reconnReq.getExtendedData().put(SequenceRequestConstant.DO_NOT_MOVE_EDIT_PARTS, true); Command cmd = targetPart.getCommand(reconnReq); return cmd; } /** * don't show feedback if the drag is forbidden (message not horizontal). */ @Override public void showSourceFeedback(Request request) { if(request instanceof BendpointRequest) { RouterKind kind = RouterKind.getKind(getConnection(), getConnection().getPoints()); if(kind == RouterKind.SELF || kind == RouterKind.HORIZONTAL || getConnection() instanceof MessageCreate){ super.showSourceFeedback(request); } } } private ConnectionRouter router; static class DummyRouter extends AbstractRouter { public void route(Connection conn) { } } protected void showMoveLineSegFeedback(BendpointRequest request) { RouterKind kind = RouterKind.getKind(getConnection(), getConnection().getPoints()); if(getHost() instanceof Message2EditPart && kind == RouterKind.SELF ){ if(router == null){ router = getConnection().getConnectionRouter(); getConnection().setConnectionRouter( new DummyRouter()); } PointList linkPoints = getConnection().getPoints().getCopy(); Point ptLoc = new Point(request.getLocation()); getConnection().translateToRelative(ptLoc); int dy = 0; if(request.getIndex() == 0) dy = ptLoc.y - linkPoints.getFirstPoint().y; else if(request.getIndex() == 2) dy = ptLoc.y - linkPoints.getLastPoint().y; // move each point on link int size = linkPoints.size(); for(int i = 0; i < size; i ++){ Point p = linkPoints.getPoint(i).translate(0, dy); linkPoints.setPoint(p, i); } // link should not exceed lifeline bounds if(checkBounds(linkPoints)){ getConnection().setPoints(linkPoints); getConnection().getLayoutManager().layout(getConnection()); } return; } if(getHost() instanceof Message4EditPart){ if(router == null){ router = getConnection().getConnectionRouter(); getConnection().setConnectionRouter( new DummyRouter()); } PointList linkPoints = getConnection().getPoints().getCopy(); Point ptLoc = new Point(request.getLocation()); getConnection().translateToRelative(ptLoc); int dy = ptLoc.y - linkPoints.getFirstPoint().y; int size = linkPoints.size(); for(int i = 0; i < size; i ++){ Point p = linkPoints.getPoint(i).translate(0, dy); linkPoints.setPoint(p, i); } if(checkBounds(linkPoints)){ getConnection().setPoints(linkPoints); getConnection().getLayoutManager().layout(getConnection()); } return; } super.showMoveLineSegFeedback(request); } protected boolean checkBounds(PointList linkPoints) { EditPart sourcePart = ((ConnectionNodeEditPart)getHost()).getSource(); if(sourcePart instanceof LifelineEditPart){ LifelineEditPart lep = (LifelineEditPart)sourcePart; NodeFigure fig = lep.getPrimaryShape().getFigureLifelineDotLineFigure().getDashLineRectangle(); Rectangle bounds = fig.getBounds().getCopy(); fig.translateToAbsolute(bounds); Rectangle conBounds = linkPoints.getBounds(); getConnection().translateToAbsolute(conBounds); // check top and bottom y limit if(conBounds.y <= bounds.y || conBounds.getBottom().y >= bounds.getBottom().y) return false; } return true; } @Override protected void eraseConnectionFeedback(BendpointRequest request, boolean removeFeedbackFigure) { getConnection().setVisible(true); super.eraseConnectionFeedback(request, removeFeedbackFigure); if(router != null) getConnection().setConnectionRouter(router); router = null; } // private boolean isHorizontal() { // Connection connection = getConnection(); // RouterKind kind = RouterKind.getKind(connection, connection.getPoints()); // // if(kind.equals(RouterKind.HORIZONTAL)) { // return true; // } // return false; // } // // final private static char TERMINAL_START_CHAR = '('; // // final private static char TERMINAL_DELIMITER_CHAR = ','; // // final private static char TERMINAL_END_CHAR = ')'; // // private static String composeTerminalString(PrecisionPoint p) { // StringBuffer s = new StringBuffer(24); // s.append(TERMINAL_START_CHAR); // 1 char // s.append(p.preciseX); // 10 chars // s.append(TERMINAL_DELIMITER_CHAR); // 1 char // s.append(p.preciseY); // 10 chars // s.append(TERMINAL_END_CHAR); // 1 char // return s.toString(); // 24 chars max (+1 for safety, i.e. for string termination) // } }