/*****************************************************************************
* Copyright (c) 2009 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.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy;
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.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequestFactory;
import org.eclipse.gmf.runtime.diagram.ui.requests.DropObjectsRequest;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.commands.wrappers.CommandProxyWithResult;
import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
import org.eclipse.papyrus.uml.diagram.common.commands.DeferredCreateCommand;
import org.eclipse.papyrus.uml.diagram.common.commands.SemanticAdapter;
import org.eclipse.papyrus.uml.diagram.common.editpolicies.CommonDiagramDragDropEditPolicy;
import org.eclipse.papyrus.uml.diagram.common.helper.DurationConstraintHelper;
import org.eclipse.papyrus.uml.diagram.common.helper.DurationObservationHelper;
import org.eclipse.papyrus.uml.diagram.common.util.DiagramEditPartsUtil;
import org.eclipse.papyrus.uml.diagram.sequence.apex.util.ApexSequenceRequestConstants;
import org.eclipse.papyrus.uml.diagram.sequence.command.CreateLocatedConnectionViewCommand;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ActionExecutionSpecificationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.BehaviorExecutionSpecificationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CombinedFragment2EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CombinedFragmentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CommentAnnotatedElementEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CommentBodyEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CommentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ConsiderIgnoreFragmentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Constraint2EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ConstraintConstrainedElementEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ConstraintEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ContinuationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.DestructionOccurrenceSpecificationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.DurationConstraintEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.DurationConstraintInMessageEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.DurationObservationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.GeneralOrderingEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionOperandEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionUseEditPart;
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.Message3EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message4EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message5EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message6EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message7EditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.MessageEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.PackageEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.StateInvariantEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.TimeConstraintEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.TimeObservationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.part.UMLDiagramEditorPlugin;
import org.eclipse.papyrus.uml.diagram.sequence.part.UMLVisualIDRegistry;
import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes;
import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceLinkMappingHelper;
import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceRequestConstant;
import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.uml2.uml.Collaboration;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.ConnectableElement;
import org.eclipse.uml2.uml.DestructionOccurrenceSpecification;
import org.eclipse.uml2.uml.DurationConstraint;
import org.eclipse.uml2.uml.DurationObservation;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.GeneralOrdering;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.IntervalConstraint;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageEnd;
import org.eclipse.uml2.uml.MessageOccurrenceSpecification;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OccurrenceSpecification;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.StateInvariant;
import org.eclipse.uml2.uml.TimeObservation;
import org.eclipse.uml2.uml.Type;
/**
* A policy to support dNd from the Model Explorer in the sequence diagram
*
*/
public class CustomDiagramDragDropEditPolicy extends CommonDiagramDragDropEditPolicy {
public static final String LIFELINE_MISSING = "There is no representation of lifeline {0}";
public static final String DIALOG_TITLE = "Element missing";
public CustomDiagramDragDropEditPolicy() {
super(SequenceLinkMappingHelper.getInstance());
}
/**
* {@inheritDoc}
*/
@Override
protected Set<Integer> getDroppableElementVisualId() {
Set<Integer> elementsVisualId = new HashSet<Integer>();
elementsVisualId.add(LifelineEditPart.VISUAL_ID);
elementsVisualId.add(ActionExecutionSpecificationEditPart.VISUAL_ID);
elementsVisualId.add(BehaviorExecutionSpecificationEditPart.VISUAL_ID);
elementsVisualId.add(InteractionUseEditPart.VISUAL_ID);
elementsVisualId.add(InteractionEditPart.VISUAL_ID);
elementsVisualId.add(InteractionOperandEditPart.VISUAL_ID);
elementsVisualId.add(CombinedFragmentEditPart.VISUAL_ID);
// CoRegion
elementsVisualId.add(CombinedFragment2EditPart.VISUAL_ID);
elementsVisualId.add(CommentAnnotatedElementEditPart.VISUAL_ID);
elementsVisualId.add(ConsiderIgnoreFragmentEditPart.VISUAL_ID);
elementsVisualId.add(ContinuationEditPart.VISUAL_ID);
elementsVisualId.add(StateInvariantEditPart.VISUAL_ID);
elementsVisualId.add(CommentEditPart.VISUAL_ID);
elementsVisualId.add(CommentBodyEditPart.VISUAL_ID);
elementsVisualId.add(ConstraintEditPart.VISUAL_ID);
elementsVisualId.add(Constraint2EditPart.VISUAL_ID);
elementsVisualId.add(ConstraintConstrainedElementEditPart.VISUAL_ID);
elementsVisualId.add(DurationObservationEditPart.VISUAL_ID);
elementsVisualId.add(TimeConstraintEditPart.VISUAL_ID);
elementsVisualId.add(TimeObservationEditPart.VISUAL_ID);
elementsVisualId.add(DurationConstraintEditPart.VISUAL_ID);
elementsVisualId.add(PackageEditPart.VISUAL_ID);
elementsVisualId.add(MessageEditPart.VISUAL_ID);
elementsVisualId.add(Message2EditPart.VISUAL_ID);
elementsVisualId.add(Message3EditPart.VISUAL_ID);
elementsVisualId.add(Message4EditPart.VISUAL_ID);
elementsVisualId.add(Message4EditPart.VISUAL_ID);
elementsVisualId.add(Message5EditPart.VISUAL_ID);
elementsVisualId.add(Message6EditPart.VISUAL_ID);
elementsVisualId.add(Message7EditPart.VISUAL_ID);
elementsVisualId.add(Message6EditPart.VISUAL_ID);
elementsVisualId.add(GeneralOrderingEditPart.VISUAL_ID);
elementsVisualId.add(DestructionOccurrenceSpecificationEditPart.VISUAL_ID);
elementsVisualId.add(StateInvariantEditPart.VISUAL_ID);
elementsVisualId.add(TimeConstraintEditPart.VISUAL_ID);
elementsVisualId.add(DurationConstraintEditPart.VISUAL_ID);
elementsVisualId.add(DurationConstraintInMessageEditPart.VISUAL_ID);
elementsVisualId.add(TimeObservationEditPart.VISUAL_ID);
elementsVisualId.add(DurationObservationEditPart.VISUAL_ID);
elementsVisualId.add(LifelineEditPart.VISUAL_ID);
// handle nodes on messages (no visual ID detected for them)
elementsVisualId.add(-1);
return elementsVisualId;
}
/**
* apex updated
*/
@Override
protected IUndoableOperation getDropObjectCommand(
DropObjectsRequest dropRequest, final EObject
droppedObject) {
IUndoableOperation dropObjectCommand = super.getDropObjectCommand(
dropRequest, droppedObject);
if (dropObjectCommand != null && dropObjectCommand.canExecute()) {
return dropObjectCommand;
}
// fix bug 364696(https://bugs.eclipse.org/bugs/show_bug.cgi?id=364696)
if (droppedObject instanceof ConnectableElement) {
return doDropConnectableElement(dropRequest,
(ConnectableElement) droppedObject);
}
/* apex added start */
if (droppedObject instanceof Type) {
return apexDoDropType(dropRequest, (Type) droppedObject);
}
/* apex added end */
return dropObjectCommand;
}
private IUndoableOperation doDropConnectableElement(
DropObjectsRequest dropRequest,
final ConnectableElement droppedObject) {
Point location = dropRequest.getLocation();
CreateViewRequest createShapeRequest = CreateViewRequestFactory
.getCreateShapeRequest(UMLElementTypes.Lifeline_3001,
UMLDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT);
createShapeRequest.setLocation(location);
ViewDescriptor viewDescriptor =createShapeRequest.getViewDescriptors().get(0);
CreateElementRequestAdapter elementAdapter =(CreateElementRequestAdapter) viewDescriptor.getElementAdapter();
CreateElementRequest createElementRequest = (CreateElementRequest)elementAdapter.getAdapter(CreateElementRequest.class);
// parameter "ConnectableElement" used in LifelineCreateCommand#doConfigure()
createElementRequest.setParameter(SequenceRequestConstant.CONNECTABLE_ELEMENT,droppedObject);
EditPart host = getHost();
Command theRealCmd = ((IGraphicalEditPart) host)
.getCommand(createShapeRequest);
if (theRealCmd != null && theRealCmd.canExecute()) {
return new CommandProxy(theRealCmd);
}
return org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE;
}
/**
* uml2.uml.Type을 drop한 경우
* @param dropRequest
* @param droppedObject
* @return
*/
private IUndoableOperation apexDoDropType(DropObjectsRequest dropRequest, final Type droppedObject) {
Point location = dropRequest.getLocation();
CreateViewRequest createShapeRequest = CreateViewRequestFactory
.getCreateShapeRequest(UMLElementTypes.Lifeline_3001,
UMLDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT);
createShapeRequest.setLocation(location);
ViewDescriptor viewDescriptor = createShapeRequest.getViewDescriptors().get(0);
CreateElementRequestAdapter elementAdapter = (CreateElementRequestAdapter)viewDescriptor.getElementAdapter();
CreateElementRequest createElementRequest = (CreateElementRequest)elementAdapter.getAdapter(CreateElementRequest.class);
EObject container = getHostObject();
while (container != null && container instanceof Collaboration == false) {
container = container.eContainer();
}
if (container == null) {
container = getHostObject();
}
ICommand createPropertyCmd = apexGetCreatePropertyCommand(container);
if (createPropertyCmd != null) {
createElementRequest.setParameter(ApexSequenceRequestConstants.APEX_CONNECTABLE_ELEMENT_CREATE_COMMAND, createPropertyCmd);
createElementRequest.setParameter(ApexSequenceRequestConstants.APEX_CONNECTABLE_ELEMENT_TYPE, droppedObject);
}
EditPart host = getHost();
Command theRealCmd = ((IGraphicalEditPart) host)
.getCommand(createShapeRequest);
if (theRealCmd != null && theRealCmd.canExecute()) {
return new CommandProxy(theRealCmd);
}
return org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE;
}
private ICommand apexGetCreatePropertyCommand(EObject container) {
IElementType type = ElementTypeRegistry.getInstance().getType("org.eclipse.papyrus.uml.Property"); //$NON-NLS-1$
IElementEditService provider = ElementEditServiceUtils.getCommandProvider(container);
CreateElementRequest createRequest = new CreateElementRequest(container, type);
ICommand createCommand = provider.getEditCommand(createRequest);
return createCommand;
}
/**
* {@inheritDoc}
*/
@Override
public IElementType getUMLElementType(int elementID) {
return UMLElementTypes.getElementType(elementID);
}
/**
* {@inheritDoc}
*/
@Override
public int getNodeVisualID(View containerView, EObject domainElement) {
return UMLVisualIDRegistry.getNodeVisualID(containerView, domainElement);
}
/**
* {@inheritDoc}
*/
@Override
public int getLinkWithClassVisualID(EObject domainElement) {
return UMLVisualIDRegistry.getLinkWithClassVisualID(domainElement);
}
@Override
protected Command getSpecificDropCommand(DropObjectsRequest dropRequest, Element semanticElement, int nodeVISUALID, int linkVISUALID) {
Point location = dropRequest.getLocation().getCopy();
// handle specifically the case when node is on a message
Command cmd = handleNodeOnMessage(semanticElement, nodeVISUALID, linkVISUALID);
if(cmd != null) {
return cmd;
}
if(nodeVISUALID != -1) {
switch(nodeVISUALID) {
case BehaviorExecutionSpecificationEditPart.VISUAL_ID:
case ActionExecutionSpecificationEditPart.VISUAL_ID:
return dropExecutionSpecification((ExecutionSpecification)semanticElement, nodeVISUALID, location);
case DestructionOccurrenceSpecificationEditPart.VISUAL_ID:
return dropDestructionOccurrence((DestructionOccurrenceSpecification)semanticElement, nodeVISUALID, location);
case StateInvariantEditPart.VISUAL_ID:
return dropStateInvariant((StateInvariant)semanticElement, nodeVISUALID, location);
case TimeConstraintEditPart.VISUAL_ID:
case DurationConstraintEditPart.VISUAL_ID:
return dropIntervalConstraintInLifeline((IntervalConstraint)semanticElement, nodeVISUALID);
case TimeObservationEditPart.VISUAL_ID:
return dropTimeObservationInLifeline((TimeObservation)semanticElement, nodeVISUALID);
case CombinedFragment2EditPart.VISUAL_ID:
return dropCoRegion((CombinedFragment)semanticElement, nodeVISUALID, location);
case CommentEditPart.VISUAL_ID:
case ConstraintEditPart.VISUAL_ID:
case Constraint2EditPart.VISUAL_ID:
case InteractionUseEditPart.VISUAL_ID:
case LifelineEditPart.VISUAL_ID:
return dropNodeElement(semanticElement, nodeVISUALID, location);
case ConsiderIgnoreFragmentEditPart.VISUAL_ID:
case CombinedFragmentEditPart.VISUAL_ID:
return dropCombinedFragment((CombinedFragment)semanticElement, nodeVISUALID, location);
case ContinuationEditPart.VISUAL_ID:
case InteractionOperandEditPart.VISUAL_ID:
return dropCompartmentNodeElement(semanticElement, nodeVISUALID, location);
default:
return UnexecutableCommand.INSTANCE;
}
}
if(linkVISUALID != -1) {
switch(linkVISUALID) {
case MessageEditPart.VISUAL_ID:
case Message2EditPart.VISUAL_ID:
case Message3EditPart.VISUAL_ID:
case Message4EditPart.VISUAL_ID:
case Message5EditPart.VISUAL_ID:
case Message6EditPart.VISUAL_ID:
case Message7EditPart.VISUAL_ID:
return dropMessage(dropRequest, semanticElement, linkVISUALID);
case GeneralOrderingEditPart.VISUAL_ID:
return dropGeneralOrdering(dropRequest, semanticElement, linkVISUALID);
default:
return UnexecutableCommand.INSTANCE;
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the drop command for the Element
*
* @param element
* the Element
* @param nodeVISUALID
* the node visual id
* @return the drop command if the Element can be dropped
*/
private Command dropNodeElement(Element element, int nodeVISUALID, Point location) {
Element parent = element.getOwner();
if (getHostObject().equals(parent)) {
List<View> existingViews = DiagramEditPartsUtil.findViews(parent, getViewer());
if (!existingViews.isEmpty()) {
EditPart parentEditPart = lookForEditPart(parent);
if (parentEditPart != null) {
return new ICommandProxy(getDefaultDropNodeCommand(parentEditPart, nodeVISUALID, location, element));
}
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the drop command for the Element
*
* @param element
* the Element
* @param nodeVISUALID
* the node visual id
* @return the drop command if the element can be dropped
*/
private Command dropCombinedFragment(CombinedFragment combinedFragment, int nodeVISUALID, Point location) {
Element parent = combinedFragment.getOwner();
Element parentContainer = parent.getOwner();
if (!(parentContainer instanceof CombinedFragment)) {
parentContainer = parent;
}
if (getHostObject().equals(parentContainer)) {
List<View> existingViews = DiagramEditPartsUtil.findViews(parent, getViewer());
if (!existingViews.isEmpty()) {
EditPart parentEditPart = lookForEditPart(parent);
if (parentEditPart instanceof GraphicalEditPart) {
// check if all lifelines coversby exist in diagram.
Rectangle bounds = null;
List<Lifeline> lifelines = combinedFragment.getCovereds();
for (Lifeline lifeline : combinedFragment.getCovereds()) {
EditPart lifelineEditPart = lookForEditPart(lifeline);
if (lifelineEditPart == null) {
Shell shell = Display.getCurrent().getActiveShell();
MessageDialog.openError(shell, DIALOG_TITLE, NLS.bind(LIFELINE_MISSING, lifeline.getName()));
return UnexecutableCommand.INSTANCE;
}
if (lifelineEditPart instanceof GraphicalEditPart) {
GraphicalEditPart graphicalEditPart = (GraphicalEditPart) lifelineEditPart;
Rectangle rectangle = graphicalEditPart.getFigure().getBounds().getCopy();
graphicalEditPart.getFigure().translateToAbsolute(rectangle);
if (bounds == null) {
bounds = rectangle;
} else {
bounds = bounds.union(rectangle);
}
}
}
if (bounds == null) {
return new ICommandProxy(getDefaultDropNodeCommand(parentEditPart, nodeVISUALID, location, combinedFragment));
}
location.x = bounds.x;
return new ICommandProxy(dropCombinedFragment(getHost(), nodeVISUALID, location, new Dimension(bounds.width, 100), combinedFragment));
}
}
}
return UnexecutableCommand.INSTANCE;
}
/*
* To extend the method in superclass with an option Dimension size,
*
*
* @param hostEP
* @param nodeVISUALID
* @param absoluteLocation
* @param size
* @param droppedObject
* @return
*/
protected ICommand dropCombinedFragment(EditPart hostEP, int nodeVISUALID, Point absoluteLocation, Dimension size, EObject droppedObject) {
IHintedType type = ((IHintedType)getUMLElementType(nodeVISUALID));
String semanticHint = null;
if (type != null) {
semanticHint = type.getSemanticHint();
}
List<View> existingViews = DiagramEditPartsUtil.findViews(droppedObject, getViewer());
// only allow one view instance of a single element by diagram
if(existingViews.isEmpty()) {
IAdaptable elementAdapter = new EObjectAdapter(droppedObject);
ViewDescriptor descriptor = new ViewDescriptor(elementAdapter, Node.class, semanticHint, ViewUtil.APPEND, false, getDiagramPreferencesHint());
CreateViewRequest createViewRequest = new CreateViewRequest(descriptor);
createViewRequest.setLocation(absoluteLocation);
createViewRequest.setSize(size);
// "ask" the host for a command associated with the
// CreateViewRequest
Command command = hostEP.getCommand(createViewRequest);
if(createViewRequest.getNewObject() instanceof List) {
for(Object object : (List<?>)createViewRequest.getNewObject()) {
if(object instanceof IAdaptable) {
DeferredCreateCommand createCommand2 = new DeferredCreateCommand(getEditingDomain(), droppedObject, (IAdaptable)object, getHost().getViewer());
command.chain(new ICommandProxy(createCommand2));
}
}
}
// set the viewdescriptor as result
// it then can be used as an adaptable to retrieve the View
return new CommandProxyWithResult(command, descriptor);
}
return org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE;
}
/**
* Get the drop command in case the element can be handled as an element in a CombinedFragment
*
* @param element
* @param nodeVISUALID
* @param location
* @return
*/
private Command dropCompartmentNodeElement(Element element, int nodeVISUALID, Point location) {
Element parent = element.getOwner();
Element directParent = parent;
if (parent instanceof InteractionOperand) {
parent = parent.getOwner();
}
if (getHostObject().equals(parent)) {
List<View> existingViews = DiagramEditPartsUtil.findViews(directParent, getViewer());
if (!existingViews.isEmpty()) {
EditPart parentEditPart = lookForEditPart(directParent);
if (parentEditPart != null) {
return new ICommandProxy(getDefaultDropNodeCommand(parentEditPart, nodeVISUALID, location, element));
}
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the drop command in case the element can be handled as a node on a message
*
* @param semanticElement
* the element being dropped from the model
* @param nodeVISUALID
* node visual id or -1
* @param linkVISUALID
* link visual id or -1
* @return the drop command if the element can be dropped as a message label node, or null otherwise
*/
private Command handleNodeOnMessage(Element semanticElement, int nodeVISUALID, int linkVISUALID) {
if(nodeVISUALID == -1 && linkVISUALID == -1) {
// detect duration observation on a message
if(semanticElement instanceof DurationObservation) {
List<NamedElement> events = ((DurationObservation)semanticElement).getEvents();
if(events.size() >= 2) {
return dropMessageNodeBetweenEvents(semanticElement, events.get(0), events.get(1));
}
}
}
if(isDurationConstraintHint(nodeVISUALID, linkVISUALID)) {
// detect duration constraint on a message
if(semanticElement instanceof DurationConstraint) {
List<Element> events = ((DurationConstraint)semanticElement).getConstrainedElements();
if(events.size() >= 2) {
return dropMessageNodeBetweenEvents(semanticElement, events.get(0), events.get(1));
}
}
}
return null;
}
/**
* Get the command to drop an element between two events in order to create a message label
*
* @param droppedElement
* the dropped element
* @param event1
* first event (of type MessageOccurrenceSpecification)
* @param event2
* second event (of type MessageOccurrenceSpecification)
* @param element
* @return the command or false if the elements can not be dropped as message label
*/
private Command dropMessageNodeBetweenEvents(Element droppedElement, Element event1, Element event2) {
if(event1 instanceof MessageOccurrenceSpecification && event2 instanceof MessageOccurrenceSpecification) {
if(!event1.equals(event2)) {
boolean endsOfSameMessage = false;
int visualId = -1;
if(droppedElement instanceof DurationConstraint) {
visualId = DurationConstraintInMessageEditPart.VISUAL_ID;
endsOfSameMessage = DurationConstraintHelper.endsOfSameMessage((OccurrenceSpecification)event1, (OccurrenceSpecification)event2);
} else if(droppedElement instanceof DurationObservation) {
visualId = DurationObservationEditPart.VISUAL_ID;
endsOfSameMessage = DurationObservationHelper.endsOfSameMessage((OccurrenceSpecification)event1, (OccurrenceSpecification)event2);
}
if(endsOfSameMessage) {
Message message = ((MessageOccurrenceSpecification)event1).getMessage();
// search a connection which matches the possessing message
DiagramEditPart diag = DiagramEditPartsUtil.getDiagramEditPart(getHost());
for(Object conn : diag.getConnections()) {
if(conn instanceof ConnectionNodeEditPart) {
EObject connElt = ((ConnectionNodeEditPart)conn).resolveSemanticElement();
if(message.equals(connElt)) {
// check that node isn't already represented, or dropping is impossible
for(Object child : ((ConnectionNodeEditPart)conn).getChildren()) {
if(child instanceof GraphicalEditPart) {
EObject childElt = ((GraphicalEditPart)child).resolveSemanticElement();
if(droppedElement.equals(childElt)) {
return null;
}
}
}
return dropNodeOnMessage((PackageableElement)droppedElement, (ConnectionNodeEditPart)conn, visualId);
}
}
}
}
}
}
return null;
}
/**
* Test whether visual ids are compatible with a duration constraint element
*
* @param nodeVISUALID
* the detected node visual id
* @param linkVISUALID
* the detected link visual id
* @return true if element may be a duration constraint
*/
private boolean isDurationConstraintHint(int nodeVISUALID, int linkVISUALID) {
if(linkVISUALID != -1) {
return false;
} else {
return nodeVISUALID == -1 || nodeVISUALID == ConstraintEditPart.VISUAL_ID || nodeVISUALID == DurationConstraintEditPart.VISUAL_ID || nodeVISUALID == DurationConstraintInMessageEditPart.VISUAL_ID;
}
}
/**
* Drop a duration observation or a duration constraint on a message edit part
*
* @param durationLabelElement
* the duration observation or duration constraint to display as message label
* @param messageEditPart
* the containing message edit part
* @param nodeVISUALID
* the label node visual id
* @return the command or UnexecutableCommand
*/
private Command dropNodeOnMessage(PackageableElement durationLabelElement, ConnectionNodeEditPart messageEditPart, int nodeVISUALID) {
IAdaptable elementAdapter = new EObjectAdapter(durationLabelElement);
ViewDescriptor descriptor = new ViewDescriptor(elementAdapter, Node.class, ((IHintedType)getUMLElementType(nodeVISUALID)).getSemanticHint(), ViewUtil.APPEND, false, getDiagramPreferencesHint());
return messageEditPart.getCommand(new CreateViewRequest(descriptor));
}
/**
* Drop a time observation on a lifeline.
*
* @param observation
* the time constraint
* @param nodeVISUALID
* the node visual id
* @return the command if the lifeline is the correct one or UnexecutableCommand
*/
private Command dropTimeObservationInLifeline(TimeObservation observation, int nodeVISUALID) {
CompoundCommand cc = new CompoundCommand("Drop");
IAdaptable elementAdapter = new EObjectAdapter(observation);
ViewDescriptor descriptor = new ViewDescriptor(elementAdapter, Node.class, ((IHintedType)getUMLElementType(nodeVISUALID)).getSemanticHint(), ViewUtil.APPEND, false, getDiagramPreferencesHint());
cc.add(getHost().getCommand(new CreateViewRequest(descriptor)));
LifelineEditPart lifelinePart = SequenceUtil.getParentLifelinePart(getHost());
if(lifelinePart != null) {
NamedElement occ1 = observation.getEvent();
if(occ1 instanceof OccurrenceSpecification) {
Point middlePoint = SequenceUtil.findLocationOfEvent(lifelinePart, (OccurrenceSpecification)occ1);
if(middlePoint != null) {
int height = getDefaultDropHeight(nodeVISUALID);
Point startPoint = middlePoint.getCopy();
if(height > 0) {
startPoint.translate(0, -height / 2);
}
Rectangle newBounds = new Rectangle(startPoint, new Dimension(-1, height));
lifelinePart.getFigure().translateToRelative(newBounds);
Point parentLoc = lifelinePart.getLocation();
newBounds.translate(parentLoc.getNegated());
SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", descriptor, newBounds);
cc.add(new ICommandProxy(setBoundsCommand));
return cc;
}
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Drop an interval constraint (duration or time) on a lifeline.
*
* @param constraint
* the interval constraint
* @param nodeVISUALID
* the node visual id
* @return the command if the lifeline is the correct one or UnexecutableCommand
*/
private Command dropIntervalConstraintInLifeline(IntervalConstraint constraint, int nodeVISUALID) {
CompoundCommand cc = new CompoundCommand("Drop");
IAdaptable elementAdapter = new EObjectAdapter(constraint);
ViewDescriptor descriptor = new ViewDescriptor(elementAdapter, Node.class, ((IHintedType)getUMLElementType(nodeVISUALID)).getSemanticHint(), ViewUtil.APPEND, false, getDiagramPreferencesHint());
cc.add(getHost().getCommand(new CreateViewRequest(descriptor)));
LifelineEditPart lifelinePart = SequenceUtil.getParentLifelinePart(getHost());
if(lifelinePart != null && constraint.getConstrainedElements().size() >= 2) {
Element occ1 = constraint.getConstrainedElements().get(0);
Element occ2 = constraint.getConstrainedElements().get(1);
if(occ1 instanceof OccurrenceSpecification && occ2 instanceof OccurrenceSpecification) {
Point startPoint = SequenceUtil.findLocationOfEvent(lifelinePart, (OccurrenceSpecification)occ1);
Point endPoint = SequenceUtil.findLocationOfEvent(lifelinePart, (OccurrenceSpecification)occ2);
if(startPoint != null && endPoint != null) {
int height = endPoint.y - startPoint.y;
Rectangle newBounds = null;
if(height < 0) {
newBounds = new Rectangle(endPoint, new Dimension(-1, -height));
} else {
newBounds = new Rectangle(startPoint, new Dimension(-1, height));
}
lifelinePart.getFigure().translateToRelative(newBounds);
Point parentLoc = lifelinePart.getLocation();
newBounds.translate(parentLoc.getNegated());
SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", descriptor, newBounds);
cc.add(new ICommandProxy(setBoundsCommand));
return cc;
}
}
} else if(lifelinePart != null && constraint.getConstrainedElements().size() == 1) {
Element occ1 = constraint.getConstrainedElements().get(0);
if(occ1 instanceof OccurrenceSpecification) {
Point middlePoint = SequenceUtil.findLocationOfEvent(lifelinePart, (OccurrenceSpecification)occ1);
if(middlePoint != null) {
int height = getDefaultDropHeight(nodeVISUALID);
Point startPoint = middlePoint.getCopy();
if(height > 0) {
startPoint.translate(0, -height / 2);
}
Rectangle newBounds = new Rectangle(startPoint, new Dimension(-1, height));
lifelinePart.getFigure().translateToRelative(newBounds);
Point parentLoc = lifelinePart.getLocation();
newBounds.translate(parentLoc.getNegated());
SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", descriptor, newBounds);
cc.add(new ICommandProxy(setBoundsCommand));
return cc;
}
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the default height to set to a drop object. This method is useful for dropped objects which must be positioned relatively to their center.
*
* @param nodeVISUALID
* the node visual id
* @return arbitrary default height for the node visual id (eventually -1)
*/
private int getDefaultDropHeight(int nodeVISUALID) {
if(TimeConstraintEditPart.VISUAL_ID == nodeVISUALID || TimeObservationEditPart.VISUAL_ID == nodeVISUALID) {
return 2;
}
return -1;
}
private Command dropStateInvariant(StateInvariant stateInvariant, int nodeVISUALID, Point location) {
// an StateInvariant covereds systematically a unique lifeline
Lifeline lifeline = stateInvariant.getCovereds().get(0);
// Check that the container view is the view of the lifeline
if(lifeline.equals(getHostObject())) {
return new ICommandProxy(getDefaultDropNodeCommand(nodeVISUALID, location, stateInvariant));
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get lifelines element which contains these existingViews
*
* @param existingViews
* the existing views.
* @return the list of lifeline.
*/
private List<Lifeline> getLifelines(List<View> existingViews) {
List<Lifeline> lifelines = new ArrayList<Lifeline>();
for(View view : existingViews) {
EObject eObject = ViewUtil.resolveSemanticElement((View)view.eContainer());
if(eObject instanceof Lifeline) {
lifelines.add((Lifeline)eObject);
}
}
return lifelines;
}
/**
* Drop a destructionEvent on a lifeline
*
* @param destructionOccurence
* the destructionEvent to drop
* @param nodeVISUALID
* the node visualID
* @return the command to drop the destructionEvent on a lifeline if allowed.
*/
private Command dropDestructionOccurrence(DestructionOccurrenceSpecification destructionOccurence, int nodeVISUALID, Point location) {
// Get all the view of this destructionEvent.
List<View> existingViews = DiagramEditPartsUtil.findViews(destructionOccurence, getViewer());
// Get the lifelines containing the graphical destructionEvent
List<Lifeline> lifelines = getLifelines(existingViews);
// If the list of lifeline already containing the destructionEvent doesn't contain the lifeline targeted.
if(!lifelines.contains(getHostObject())) {
Lifeline lifeline = (Lifeline)getHostObject();
for(InteractionFragment ift : lifeline.getCoveredBys()) {
if(ift instanceof DestructionOccurrenceSpecification) {
DestructionOccurrenceSpecification occurrenceSpecification = (DestructionOccurrenceSpecification)ift;
// if the event of the occurrenceSpecification is the DestructionEvent, create the command
if(destructionOccurence.equals(occurrenceSpecification)) {
return new ICommandProxy(getDefaultDropNodeCommand(nodeVISUALID, location, destructionOccurence));
}
}
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the command to drop an execution specification node
*
* @param es
* execution specification
* @param nodeVISUALID
* the execution specification's visual id
* @param location
* the location of the drop request
* @return the drop command
*/
private Command dropExecutionSpecification(ExecutionSpecification es, int nodeVISUALID, Point location) {
List<View> existingViews = DiagramEditPartsUtil.findViews(es, getViewer());
// only allow one view instance of a single element by diagram
if(existingViews.isEmpty()) {
// Find the lifeline of the ES
if(es.getStart() != null && !es.getStart().getCovereds().isEmpty()) {
// an Occurrence Specification covers systematically a unique lifeline
Lifeline lifeline = es.getStart().getCovereds().get(0);
// Check that the container view is the view of the lifeline
if(lifeline.equals(getHostObject())) {
//return new ICommandProxy(getDefaultDropNodeCommand(nodeVISUALID, location, es));
IHintedType type = ((IHintedType)getUMLElementType(nodeVISUALID));
String semanticHint = null;
if(type != null) {
semanticHint = type.getSemanticHint();
}
IAdaptable elementAdapter = new EObjectAdapter(es);
ViewDescriptor descriptor = new ViewDescriptor(elementAdapter, Node.class, semanticHint, ViewUtil.APPEND, false, getDiagramPreferencesHint());
CreateViewRequest createViewRequest = new CreateViewRequest(descriptor);
// find best bounds
Rectangle bounds = getExecutionSpecificationBounds(es);
if(bounds != null) {
createViewRequest.setLocation(bounds.getLocation());
createViewRequest.setSize(bounds.getSize());
} else {
createViewRequest.setLocation(location);
}
// "ask" the host for a command associated with the CreateViewRequest
Command command = getHost().getCommand(createViewRequest);
// set the viewdescriptor as result
// it then can be used as an adaptable to retrieve the View
return new ICommandProxy(new CommandProxyWithResult(command, descriptor));
}
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the command to drop an code region node
*
* @param combinedFragment
* @param nodeVISUALID
* @param location
* @return
*/
private Command dropCoRegion(CombinedFragment combinedFragment, int nodeVISUALID, Point location) {
List<View> existingViews = DiagramEditPartsUtil.findViews(combinedFragment, getViewer());
// only allow one view instance of a single element by diagram
if(existingViews.isEmpty()) {
IGraphicalEditPart hostEditpart = (IGraphicalEditPart) getHost();
EObject element = hostEditpart.getNotationView().getElement();
if (element instanceof Lifeline) {
IHintedType type = ((IHintedType)getUMLElementType(nodeVISUALID));
String semanticHint = null;
if (type != null) {
semanticHint = type.getSemanticHint();
}
IAdaptable elementAdapter = new EObjectAdapter(combinedFragment);
ViewDescriptor descriptor = new ViewDescriptor(elementAdapter, Node.class, semanticHint, ViewUtil.APPEND, false, getDiagramPreferencesHint());
CreateViewRequest createViewRequest = new CreateViewRequest(descriptor);
createViewRequest.setLocation(location);
// "ask" the host for a command associated with the CreateViewRequest
Command command = getHost().getCommand(createViewRequest);
// set the viewdescriptor as result
// it then can be used as an adaptable to retrieve the View
return new ICommandProxy(new CommandProxyWithResult(command, descriptor));
}
}
return UnexecutableCommand.INSTANCE;
}
/**
* Get the advised bounds to drop an execution specification
*
* @param es
* the dropped execution specification
* @return bounds of the es in absolute coordinates or null
*/
private Rectangle getExecutionSpecificationBounds(ExecutionSpecification es) {
Point startLocation = null;
Point finishLocation = null;
Rectangle possibleStartLocations = null;
Rectangle possibleFinishLocations = null;
// end events of the link
OccurrenceSpecification startEvent = es.getStart();
OccurrenceSpecification finishEvent = es.getFinish();
if(startEvent != null && finishEvent != null && getHost() instanceof LifelineEditPart) {
LifelineEditPart hostLifeline = (LifelineEditPart)getHost();
// find location constraints for source
startLocation = SequenceUtil.findLocationOfEvent((LifelineEditPart)getHost(), startEvent);
if(startLocation == null) {
possibleStartLocations = SequenceUtil.findPossibleLocationsForEvent(hostLifeline, startEvent);
}
// find location constraints for target
finishLocation = SequenceUtil.findLocationOfEvent(hostLifeline, finishEvent);
if(finishLocation == null) {
possibleFinishLocations = SequenceUtil.findPossibleLocationsForEvent(hostLifeline, finishEvent);
}
// find start and finish locations with correct y (start.y < finish.y) and proportions
if(startLocation == null) {
if(finishLocation != null) {
int top = possibleStartLocations.x;
int bottom = possibleStartLocations.bottom();
if(top > finishLocation.y) {
return null;
} else {
startLocation = possibleStartLocations.getTop();
startLocation.y = (top + Math.min(bottom, finishLocation.y)) / 2;
}
} else {
int topS = possibleStartLocations.y;
int bottomS = possibleStartLocations.bottom();
int topF = possibleFinishLocations.y;
int bottomF = possibleFinishLocations.bottom();
if(topS > bottomF) {
return null;
} else {
startLocation = possibleStartLocations.getTop();
finishLocation = possibleFinishLocations.getBottom();
if(bottomS<topF){
startLocation.y = (topS + bottomS) / 2;
finishLocation.y = (topF + bottomF) / 2;
} else {
startLocation.y = (topS + bottomS + topS + topF) / 4;
finishLocation.y = (bottomF + topF + bottomF + bottomS) / 4;
}
}
}
}
if(finishLocation == null) {
// startLocation != null
int top = possibleFinishLocations.y;
int bottom = possibleFinishLocations.bottom();
if(bottom < startLocation.y) {
return null;
} else {
finishLocation = possibleFinishLocations.getBottom();
finishLocation.y = (bottom + Math.max(top, startLocation.y)) / 2;
}
}
// deduce bounds
Rectangle result = new Rectangle(startLocation, finishLocation);
result.width = LifelineXYLayoutEditPolicy.EXECUTION_INIT_WIDTH;
return result;
}
return null;
}
/**
* Get the command to drop a message link
*
* @param dropRequest
* request to drop
* @param semanticLink
* message link
* @param linkVISUALID
* the message's visual id
* @return the drop command
*/
private Command dropMessage(DropObjectsRequest dropRequest, Element semanticLink, int linkVISUALID) {
Collection<?> sources = SequenceLinkMappingHelper.getInstance().getSource(semanticLink);
Collection<?> targets = SequenceLinkMappingHelper.getInstance().getTarget(semanticLink);
if(!sources.isEmpty() && !targets.isEmpty()) {
Element source = (Element)sources.toArray()[0];
Element target = (Element)targets.toArray()[0];
return getDropLocatedLinkCommand(dropRequest, source, target, linkVISUALID, semanticLink);
} else {
return UnexecutableCommand.INSTANCE;
}
}
/**
* The method provides command to create the binary link into the diagram. If the source and the
* target views do not exist, these views will be created.
*
* This implementation is very similar to
* {@link CommonDiagramDragDropEditPolicy#dropBinaryLink(CompositeCommand, Element, Element, int, Point, Element)}.
*
* @param dropRequest
* the drop request
* @param cc
* the composite command that will contain the set of command to create the binary
* link
* @param source
* the element source of the link
* @param target
* the element target of the link
* @param linkVISUALID
* the link VISUALID used to create the view
* @param location
* the location the location where the view will be be created
* @param semanticLink
* the semantic link that will be attached to the view
*
* @return the composite command
*/
protected Command getDropLocatedLinkCommand(DropObjectsRequest dropRequest, Element source, Element target, int linkVISUALID, Element semanticLink) {
// look for editpart
GraphicalEditPart sourceEditPart = (GraphicalEditPart)lookForEditPart(source);
GraphicalEditPart targetEditPart = (GraphicalEditPart)lookForEditPart(target);
CompositeCommand cc = new CompositeCommand("Drop");
// descriptor of the link
CreateConnectionViewRequest.ConnectionViewDescriptor linkdescriptor = new CreateConnectionViewRequest.ConnectionViewDescriptor(getUMLElementType(linkVISUALID), ((IHintedType)getUMLElementType(linkVISUALID)).getSemanticHint(), getDiagramPreferencesHint());
// get source and target adapters, creating the add commands if necessary
IAdaptable sourceAdapter = null;
IAdaptable targetAdapter = null;
if(sourceEditPart == null) {
ICommand createCommand = getDefaultDropNodeCommand(getLinkSourceDropLocation(dropRequest.getLocation(), source, target), source);
cc.add(createCommand);
sourceAdapter = (IAdaptable)createCommand.getCommandResult().getReturnValue();
} else {
sourceAdapter = new SemanticAdapter(null, sourceEditPart.getModel());
}
if(targetEditPart == null) {
ICommand createCommand = getDefaultDropNodeCommand(getLinkTargetDropLocation(dropRequest.getLocation(), source, target), target);
cc.add(createCommand);
targetAdapter = (IAdaptable)createCommand.getCommandResult().getReturnValue();
} else {
targetAdapter = new SemanticAdapter(null, targetEditPart.getModel());
}
CreateLocatedConnectionViewCommand aLinkCommand = new CreateLocatedConnectionViewCommand(getEditingDomain(), ((IHintedType)getUMLElementType(linkVISUALID)).getSemanticHint(), sourceAdapter, targetAdapter, getViewer(), getDiagramPreferencesHint(), linkdescriptor, null);
aLinkCommand.setElement(semanticLink);
Point[] sourceAndTarget = getLinkSourceAndTargetLocations(semanticLink, sourceEditPart, targetEditPart);
aLinkCommand.setLocations(sourceAndTarget[0], sourceAndTarget[1]);
cc.compose(aLinkCommand);
return new ICommandProxy(cc);
}
/**
* Get the source and target recommended points for creating the link
*
* @param semanticLink
* link to create
* @param sourceEditPart
* edit part source of the link
* @param targetEditPart
* edit part target of the link
* @return a point array of size 2, with eventually null values (when no point constraint). Index 0 : source location, 1 : target location
*/
private Point[] getLinkSourceAndTargetLocations(Element semanticLink, GraphicalEditPart sourceEditPart, GraphicalEditPart targetEditPart) {
// index 0 : source location, 1 : target location
Point[] sourceAndTarget = new Point[]{ null, null };
// end events of the link
OccurrenceSpecification sourceEvent = null;
OccurrenceSpecification targetEvent = null;
if(semanticLink instanceof Message) {
MessageEnd sendEvent = ((Message)semanticLink).getSendEvent();
if(sendEvent instanceof OccurrenceSpecification) {
sourceEvent = (OccurrenceSpecification)sendEvent;
}
MessageEnd rcvEvent = ((Message)semanticLink).getReceiveEvent();
if(rcvEvent instanceof OccurrenceSpecification) {
targetEvent = (OccurrenceSpecification)rcvEvent;
}
} else if(semanticLink instanceof GeneralOrdering) {
sourceEvent = ((GeneralOrdering)semanticLink).getBefore();
targetEvent = ((GeneralOrdering)semanticLink).getAfter();
}
if(sourceEvent != null || targetEvent != null) {
Rectangle possibleSourceLocations = null;
Rectangle possibleTargetLocations = null;
// find location constraints for source
if(sourceEvent != null && sourceEditPart instanceof LifelineEditPart) {
sourceAndTarget[0] = SequenceUtil.findLocationOfEvent((LifelineEditPart)sourceEditPart, sourceEvent);
if(sourceAndTarget[0] == null) {
possibleSourceLocations = SequenceUtil.findPossibleLocationsForEvent((LifelineEditPart)sourceEditPart, sourceEvent);
}
}
// find location constraints for target
if(targetEvent != null && targetEditPart instanceof LifelineEditPart) {
sourceAndTarget[1] = SequenceUtil.findLocationOfEvent((LifelineEditPart)targetEditPart, targetEvent);
if(sourceAndTarget[1] == null) {
possibleTargetLocations = SequenceUtil.findPossibleLocationsForEvent((LifelineEditPart)targetEditPart, targetEvent);
}
}
// deduce a possibility
if(sourceAndTarget[0] == null && possibleSourceLocations != null) {
// we must fix the source
if(sourceAndTarget[1] == null && possibleTargetLocations == null) {
// no target constraint, take center for source
sourceAndTarget[0] = possibleSourceLocations.getCenter();
} else if(sourceAndTarget[1] != null) {
// target is fixed, find arranging source
int topSource = possibleSourceLocations.y;
int centerSource = possibleSourceLocations.getCenter().y;
if(sourceAndTarget[1].y < topSource) {
// we would draw an uphill message (forbidden).
// return best locations (command will not execute correctly and handle error report)
sourceAndTarget[0] = possibleSourceLocations.getTop();
} else if(centerSource <= sourceAndTarget[1].y) {
// simply fix to the center of constraint
sourceAndTarget[0] = possibleSourceLocations.getCenter();
} else {
// horizontal message makes source as near as possible to the center
sourceAndTarget[0] = possibleSourceLocations.getCenter();
sourceAndTarget[0].y = sourceAndTarget[1].y;
}
} else {
// possibleTargetLocations !=null
// find arranging target and source
int centerTarget = possibleTargetLocations.getCenter().y;
int bottomTarget = possibleTargetLocations.bottom();
int topSource = possibleSourceLocations.y;
int centerSource = possibleSourceLocations.getCenter().y;
if(bottomTarget < topSource) {
// we would draw an uphill message (forbidden).
// return best locations (command will not execute correctly and handle error report)
sourceAndTarget[0] = possibleSourceLocations.getTop();
sourceAndTarget[1] = possibleTargetLocations.getBottom();
} else if(centerSource <= centerTarget) {
// simply fix to centers
sourceAndTarget[0] = possibleSourceLocations.getCenter();
sourceAndTarget[1] = possibleTargetLocations.getCenter();
} else {
// horizontal message makes source and target as near as possible to the centers
sourceAndTarget[0] = possibleSourceLocations.getCenter();
sourceAndTarget[0].y = (topSource + bottomTarget) / 2;
sourceAndTarget[1] = possibleTargetLocations.getCenter();
sourceAndTarget[1].y = (topSource + bottomTarget) / 2;
}
}
}
if(sourceAndTarget[1] == null && possibleTargetLocations != null) {
// we must fix the target
// fixedSourceLocation == null => possibleSourceLocations == null
// source is fixed, find arranging target
int centerTarget = possibleTargetLocations.getCenter().y;
int bottomTarget = possibleTargetLocations.bottom();
if(sourceAndTarget[0] == null) {
// simply fix to the center of constraint
sourceAndTarget[1] = possibleTargetLocations.getCenter();
} else if(bottomTarget < sourceAndTarget[0].y) {
// we would draw an uphill message (forbidden).
// return best locations (command will not execute correctly and handle error report)
sourceAndTarget[1] = possibleTargetLocations.getBottom();
} else if(sourceAndTarget[0].y <= centerTarget) {
// simply fix to the center of constraint
sourceAndTarget[1] = possibleTargetLocations.getCenter();
} else {
// horizontal message makes target as near as possible to the center
sourceAndTarget[1] = possibleTargetLocations.getCenter();
sourceAndTarget[1].y = sourceAndTarget[0].y;
}
}
}
return sourceAndTarget;
}
/**
* Get the command to drop a general ordering link
*
* @param dropRequest
* request to drop
* @param semanticLink
* general ordering link
* @param linkVISUALID
* the link's visual id
* @return the drop command
*/
private Command dropGeneralOrdering(DropObjectsRequest dropRequest, Element semanticLink, int linkVISUALID) {
Collection<?> sources = SequenceLinkMappingHelper.getInstance().getSource(semanticLink);
Collection<?> targets = SequenceLinkMappingHelper.getInstance().getTarget(semanticLink);
if(!sources.isEmpty() && !targets.isEmpty()) {
Element source = (Element)sources.toArray()[0];
Element target = (Element)targets.toArray()[0];
return getDropLocatedLinkCommand(dropRequest, source, target, linkVISUALID, semanticLink);
} else {
return UnexecutableCommand.INSTANCE;
}
}
}