/*****************************************************************************
* 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.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.ConnectionRouter;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.Polyline;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeConnectionRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.papyrus.uml.diagram.sequence.draw2d.routers.MessageRouter;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message4EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes;
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.LifelineMessageCreateHelper;
/**
* A specific policy to handle :
* - Message aspects inherited from {@link SequenceGraphicalNodeEditPolicy}.
* - Time/duration move when a message end or an execution is moved.
* - Duration constraint/observation creation feedback.
* - Creation of general ordering links.
* This edit policy is intended to be installed on parts which represent a lifeline or which are contained within a lifeline part.
*/
public class LifelineChildGraphicalNodeEditPolicy extends SequenceGraphicalNodeEditPolicy {
/** the feedback for creating a duration constraint node */
private Polyline durationCreationFeedback = null;
/** the router to use for messages */
public static ConnectionRouter messageRouter = new MessageRouter();
@Override
public Command getCommand(Request request) {
if(RequestConstants.REQ_CONNECTION_START.equals(request.getType())) {
if(request instanceof CreateConnectionViewAndElementRequest) {
return getConnectionAndRelationshipCreateCommand((CreateConnectionViewAndElementRequest)request);
} else if(request instanceof CreateUnspecifiedTypeConnectionRequest) {
return getUnspecifiedConnectionCreateCommand((CreateUnspecifiedTypeConnectionRequest)request);
}
} else if(RequestConstants.REQ_CONNECTION_END.equals(request.getType())) {
if(request instanceof CreateConnectionViewAndElementRequest) {
return getConnectionAndRelationshipCompleteCommand((CreateConnectionViewAndElementRequest)request);
} else if(request instanceof CreateUnspecifiedTypeConnectionRequest) {
return getUnspecifiedConnectionCompleteCommand((CreateUnspecifiedTypeConnectionRequest)request);
}
}
return super.getCommand(request);
}
/**
* Gets the command to start the creation of a new connection and
* relationship (if applicable) for a unspecified type request. This will
* update all the individual requests appropriately.
*
* @param request
* the unspecified type request
* @return the command
*/
private Command getUnspecifiedConnectionCreateCommand(final CreateUnspecifiedTypeConnectionRequest request) {
if(request.isDirectionReversed()) {
return new Command() {
/**
* All we know is the target and the possible relationship
* types. At this point, there is no way to validate the
* commands for this scenario.
*/
public boolean canExecute() {
return true;
}
};
} else {
// Get the start command for each individual request, this will
// update each request as required.
final List commands = new ArrayList();
for(Iterator iter = request.getAllRequests().iterator(); iter.hasNext();) {
Request individualRequest = (Request)iter.next();
Command cmd = null;
if(individualRequest instanceof CreateConnectionViewAndElementRequest) {
cmd = getConnectionAndRelationshipCreateCommand((CreateConnectionViewAndElementRequest)individualRequest);
} else if(individualRequest instanceof CreateConnectionViewRequest) {
cmd = getConnectionCreateCommand((CreateConnectionViewRequest)individualRequest);
}
if(cmd != null && cmd.canExecute()) {
commands.add(cmd);
}
}
if(commands.isEmpty()) {
// GEF's AbstractConnectionCreationTool expects a null command
// when the gesture should be disabled.
return null;
}
// return an executable command that does nothing
return new Command() {/* do nothing */
};
}
}
/**
* Get the command to reconnect the source and move associated time/duration constraints/observation.
*
* @see org.eclipse.papyrus.uml.diagram.sequence.edit.policies.SequenceGraphicalNodeEditPolicy#getReconnectSourceCommand(org.eclipse.gef.requests.ReconnectRequest)
*
* @param request
* the reconnection request
* @return the command
*/
@Override
protected Command getReconnectSourceCommand(ReconnectRequest request) {
Command command = super.getReconnectSourceCommand(request);
if(command != null) {
command = OccurrenceSpecificationMoveHelper.completeReconnectConnectionCommand(command, request, getConnectableEditPart());
if(request.getConnectionEditPart() instanceof Message4EditPart && request.getTarget() instanceof LifelineEditPart){
LifelineEditPart newSource = (LifelineEditPart) request.getTarget();
LifelineEditPart target = (LifelineEditPart) request.getConnectionEditPart().getTarget();
command = LifelineMessageCreateHelper.moveLifelineDown(command, target, newSource.getFigure().getBounds().getLocation().getCopy());
}
}
return command;
}
/**
* Get the command to reconnect the target and move associated time/duration constraints/observation.
*
* @see org.eclipse.papyrus.uml.diagram.sequence.edit.policies.SequenceGraphicalNodeEditPolicy#getReconnectTargetCommand(org.eclipse.gef.requests.ReconnectRequest)
*
* @param request
* the reconnection request
* @return the command
*/
@Override
protected Command getReconnectTargetCommand(ReconnectRequest request) {
Command command = super.getReconnectTargetCommand(request);
if(command != null) {
command = OccurrenceSpecificationMoveHelper.completeReconnectConnectionCommand(command, request, getConnectableEditPart());
if(request.getConnectionEditPart() instanceof Message4EditPart && request.getTarget() instanceof LifelineEditPart){
command = LifelineMessageCreateHelper.reconnectMessageCreateTarget(request, command);
}
}
return command;
}
/**
* Show the feedback for creating a duration constraint from this edit part
*
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#showSourceFeedback(org.eclipse.gef.Request)
* @param request
* creation request
*/
@Override
public void showSourceFeedback(Request request) {
if(request instanceof CreateUnspecifiedTypeRequest) {
Object hintedType = ((CreateUnspecifiedTypeRequest)request).getElementTypes().get(0);
CreateRequest req = null;
if(UMLElementTypes.DurationConstraint_3021.equals(hintedType)) {
req = ((CreateUnspecifiedTypeRequest)request).getRequestForType(UMLElementTypes.DurationConstraint_3021);
} else if(UMLElementTypes.DurationObservation_3024.equals(hintedType)) {
req = ((CreateUnspecifiedTypeRequest)request).getRequestForType(UMLElementTypes.DurationObservation_3024);
}
if(req != null) {
Object initLocation = req.getExtendedData().get(SequenceRequestConstant.OCCURRENCE_SPECIFICATION_LOCATION);
if(initLocation instanceof Point) {
Point startPoint = ((Point)initLocation).getCopy();
Point targetPoint = ((CreateUnspecifiedTypeRequest)request).getLocation().getCopy();
getFeedbackLayer().translateToRelative(startPoint);
getFeedbackLayer().translateToRelative(targetPoint);
if(durationCreationFeedback == null) {
durationCreationFeedback = new Polyline();
durationCreationFeedback.setLineWidth(1);
durationCreationFeedback.setLineStyle(Graphics.LINE_DASHDOT);
durationCreationFeedback.setForegroundColor(((IGraphicalEditPart)getHost()).getFigure().getLocalForegroundColor());
addFeedback(durationCreationFeedback);
}
durationCreationFeedback.setStart(startPoint);
durationCreationFeedback.setEnd(targetPoint);
return;
}
}
}
super.showSourceFeedback(request);
}
/**
* Erase the feedback for creating a duration constraint from this edit part
*
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#eraseSourceFeedback(org.eclipse.gef.Request)
* @param request
* creation request
*/
@Override
public void eraseSourceFeedback(Request request) {
super.eraseSourceFeedback(request);
if(durationCreationFeedback != null)
removeFeedback(durationCreationFeedback);
durationCreationFeedback = null;
}
/**
* Get the replacing connection router for routing messages correctly
*
* @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getDummyConnectionRouter(org.eclipse.gef.requests.CreateConnectionRequest)
*/
protected ConnectionRouter getDummyConnectionRouter(CreateConnectionRequest req) {
return messageRouter;
}
}