/***************************************************************************** * 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.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PrecisionPoint; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.transaction.TransactionalEditingDomain; 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.requests.ChangeBoundsRequest; import org.eclipse.gef.requests.ReconnectRequest; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.common.core.util.StringStatics; import org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; 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.ConnectionEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart; import org.eclipse.gmf.runtime.diagram.ui.figures.BorderedNodeFigure; import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor; import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.notation.IdentityAnchor; import org.eclipse.gmf.runtime.notation.NotationFactory; import org.eclipse.gmf.runtime.notation.NotationPackage; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.gmf.runtime.notation.impl.ConnectorImpl; import org.eclipse.papyrus.uml.diagram.common.helper.InteractionFragmentHelper; import org.eclipse.papyrus.uml.diagram.common.util.DiagramEditPartsUtil; import org.eclipse.papyrus.uml.diagram.sequence.apex.draw2d.anchors.ApexHorizontalAnchor; import org.eclipse.papyrus.uml.diagram.sequence.apex.interfaces.IApexLifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ObservationLinkEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.TimeObservationLabelEditPart; import org.eclipse.uml2.common.util.CacheAdapter; import org.eclipse.uml2.uml.DestructionOccurrenceSpecification; import org.eclipse.uml2.uml.DurationConstraint; 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.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.TimeConstraint; import org.eclipse.uml2.uml.TimeObservation; /** * This Helper must be used for performing move/reconnect operations which modify the location of an OccurrenceSpecification. * * @author vhemery */ public class OccurrenceSpecificationMoveHelper { /** * Get the complete command to move or reconnect all edit parts attached to one or two occurrence specification(s). * * @param movedOccurrenceSpecification1 * first moved occurrence specification * @param movedOccurrenceSpecification2 * second moved occurrence specification (or null) * @param yLocation1 * y location where first occurrence specification is moved * @param yLocation2 * y location where second occurrence specification is moved (or -1) * @param lifelinePart * lifeline edit part containing the moved element * @param notToMoveEditParts * list of edit parts which must not be moved in the created command * @return command to move all edit parts linked to the occurrence specifications or null */ public static Command getMoveOccurrenceSpecificationsCommand(OccurrenceSpecification movedOccurrenceSpecification1, OccurrenceSpecification movedOccurrenceSpecification2, int yLocation1, int yLocation2, LifelineEditPart lifelinePart, List<EditPart> notToMoveEditParts) { // the global command which shall be completed and returned CompoundCommand globalCmd = new CompoundCommand(); // move the corresponding execution specification if necessary Command command = getMoveExecutionSpecificationCommand(movedOccurrenceSpecification1, movedOccurrenceSpecification2, yLocation1, yLocation2, lifelinePart, notToMoveEditParts); if(command != null) { globalCmd.add(command); } // reconnect the corresponding message(s) if necessary if(movedOccurrenceSpecification1 instanceof MessageOccurrenceSpecification) { command = getReconnectMessageCommand(movedOccurrenceSpecification1, yLocation1, lifelinePart, notToMoveEditParts); if(command != null) { globalCmd.add(command); } } if(movedOccurrenceSpecification2 instanceof MessageOccurrenceSpecification) { command = getReconnectMessageCommand(movedOccurrenceSpecification2, yLocation2, lifelinePart, notToMoveEditParts); if(command != null) { globalCmd.add(command); } } // move the corresponding time/duration constraints/observations if necessary command = getMoveTimeElementsCommand(movedOccurrenceSpecification1, movedOccurrenceSpecification2, yLocation1, yLocation2, lifelinePart, notToMoveEditParts); if(command != null) { globalCmd.add(command); } // reconnect the corresponding general ordering(s) if necessary command = getReconnectGeneralOrderingCommand(movedOccurrenceSpecification1, yLocation1, lifelinePart, notToMoveEditParts); if(command != null) { globalCmd.add(command); } if(movedOccurrenceSpecification2 != null) { command = getReconnectGeneralOrderingCommand(movedOccurrenceSpecification2, yLocation2, lifelinePart, notToMoveEditParts); if(command != null) { globalCmd.add(command); } } // return null rather than an empty non executable command if(globalCmd.isEmpty()) { return null; } return globalCmd; } /** * Get the complete command to move message occurrence specification. * * @param movedOccurrenceSpecification * moved occurrence specification * @param yLocation * y location where occurrence specification is moved * @param newBounds * source or target edit part's bounds * @param lifelinePart * lifeline edit part containing the moved element * @param notToMoveEditParts * list of edit parts which must not be moved in the created command * @return command to move all edit parts linked to the occurrence specifications or null */ public static Command getMoveMessageOccurrenceSpecificationsCommand(OccurrenceSpecification movedOccurrenceSpecification, int yLocation, Rectangle newBounds, EditPart childToReconnectTo, LifelineEditPart lifelinePart, List<EditPart> notToMoveEditParts) { // the global command which shall be completed and returned CompoundCommand command = new CompoundCommand(); if (newBounds == null) { return OccurrenceSpecificationMoveHelper.getMoveOccurrenceSpecificationsCommand(movedOccurrenceSpecification, null, yLocation, -1, lifelinePart, notToMoveEditParts); } if(movedOccurrenceSpecification instanceof MessageOccurrenceSpecification) { Point referencePoint = getReferencePoint(lifelinePart, movedOccurrenceSpecification, yLocation); if (childToReconnectTo instanceof IGraphicalEditPart) { // reconnect message from the event Message message = ((MessageOccurrenceSpecification)movedOccurrenceSpecification).getMessage(); if(message != null && movedOccurrenceSpecification.equals(message.getSendEvent())) { Collection<Setting> settings = CacheAdapter.getInstance().getNonNavigableInverseReferences(message); for(Setting ref : settings) { if(NotationPackage.eINSTANCE.getView_Element().equals(ref.getEStructuralFeature())) { View view = (View)ref.getEObject(); EditPart part = DiagramEditPartsUtil.getEditPartFromView(view, lifelinePart); // the message part must start or finish on the lifeline (with the event) if(part instanceof ConnectionNodeEditPart && !notToMoveEditParts.contains(part)) { SetConnectionAnchorsCommand scaCmd = new SetConnectionAnchorsCommand(((IGraphicalEditPart)childToReconnectTo).getEditingDomain(), StringStatics.BLANK); PrecisionPoint pt = BaseSlidableAnchor.getAnchorRelativeLocation(referencePoint, newBounds); IFigure figure = ((IGraphicalEditPart)childToReconnectTo).getFigure(); /* apex improved start */ EObject eObj = ((IGraphicalEditPart) childToReconnectTo).resolveSemanticElement(); if ( eObj instanceof Lifeline ) { figure = ((IApexLifelineEditPart)childToReconnectTo).getNodeFigure(); } ConnectionAnchor sourceAnchor = new ApexHorizontalAnchor(figure, pt); scaCmd.setEdgeAdaptor(new EObjectAdapter(view)); scaCmd.setNewSourceTerminal(((INodeEditPart)part).mapConnectionAnchorToTerminal(sourceAnchor)); command.add(new ICommandProxy(scaCmd)); // update enclosing interaction fragment Command updateIFrag = SequenceUtil.createUpdateEnclosingInteractionCommand((MessageOccurrenceSpecification)movedOccurrenceSpecification, referencePoint, lifelinePart); if(updateIFrag != null && updateIFrag.canExecute()) { command.add(updateIFrag); } /* apex improved end */ /* apex replaced if (childToReconnectTo instanceof LifelineEditPart) { figure = ((LifelineEditPart)childToReconnectTo).getNodeFigure(); } ConnectionAnchor sourceAnchor = new ApexHorizontalAnchor(figure, pt); scaCmd.setEdgeAdaptor(new EObjectAdapter(view)); scaCmd.setNewSourceTerminal(((INodeEditPart)part).mapConnectionAnchorToTerminal(sourceAnchor)); command.add(new ICommandProxy(scaCmd)); // update enclosing interaction fragment Command updateIFrag = SequenceUtil.createUpdateEnclosingInteractionCommand((MessageOccurrenceSpecification)movedOccurrenceSpecification, referencePoint, lifelinePart); if(updateIFrag != null && updateIFrag.canExecute()) { command.add(updateIFrag); } */ } } } } // reconnect message to the event if(message != null && movedOccurrenceSpecification.equals(message.getReceiveEvent())) { Collection<Setting> settings = CacheAdapter.getInstance().getNonNavigableInverseReferences(message); for(Setting ref : settings) { if(NotationPackage.eINSTANCE.getView_Element().equals(ref.getEStructuralFeature())) { View view = (View)ref.getEObject(); EditPart part = DiagramEditPartsUtil.getEditPartFromView(view, lifelinePart); // the message part must start or finish on the lifeline (with the event) if(part instanceof ConnectionNodeEditPart && !notToMoveEditParts.contains(part)) { SetConnectionAnchorsCommand scaCmd = new SetConnectionAnchorsCommand(((IGraphicalEditPart)childToReconnectTo).getEditingDomain(), StringStatics.BLANK); PrecisionPoint pt = BaseSlidableAnchor.getAnchorRelativeLocation(referencePoint, newBounds); IFigure figure = ((IGraphicalEditPart)childToReconnectTo).getFigure(); /* apex improved start */ EObject eObj = ((IGraphicalEditPart) childToReconnectTo).resolveSemanticElement(); if (eObj instanceof Lifeline) { figure = ((IApexLifelineEditPart)childToReconnectTo).getNodeFigure(); } ConnectionAnchor targetAnchor = new ApexHorizontalAnchor(figure, pt); scaCmd.setEdgeAdaptor(new EObjectAdapter(view)); scaCmd.setNewSourceTerminal(((INodeEditPart)part).mapConnectionAnchorToTerminal(targetAnchor)); command.add(new ICommandProxy(scaCmd)); // update enclosing interaction fragment Command updateIFrag = SequenceUtil.createUpdateEnclosingInteractionCommand((MessageOccurrenceSpecification)movedOccurrenceSpecification, referencePoint, lifelinePart); if(updateIFrag != null && updateIFrag.canExecute()) { command.add(updateIFrag); } /* apex improved end */ /* apex replaced if (childToReconnectTo instanceof LifelineEditPart) { figure = ((LifelineEditPart)childToReconnectTo).getNodeFigure(); } ConnectionAnchor targetAnchor = new ApexHorizontalAnchor(figure, pt); scaCmd.setEdgeAdaptor(new EObjectAdapter(view)); scaCmd.setNewSourceTerminal(((INodeEditPart)part).mapConnectionAnchorToTerminal(targetAnchor)); command.add(new ICommandProxy(scaCmd)); // update enclosing interaction fragment Command updateIFrag = SequenceUtil.createUpdateEnclosingInteractionCommand((MessageOccurrenceSpecification)movedOccurrenceSpecification, referencePoint, lifelinePart); if(updateIFrag != null && updateIFrag.canExecute()) { command.add(updateIFrag); } */ } } } } } } // return null rather than an empty non executable command if(command.isEmpty()) { return null; } return command; } /** * Get the reference point to reconnect or resize edit parts at the given y location * * @param lifelinePart * lifeline edit part containing the moved element * @param movedOccurrenceSpecification * the moving occurrence specification which a reference point is searched for * @param yLocation * y location * @return reference point on the lifeline */ private static Point getReferencePoint(LifelineEditPart lifelinePart, OccurrenceSpecification movedOccurrenceSpecification, int yLocation) { Point referencePoint = SequenceUtil.findLocationOfEvent(lifelinePart, movedOccurrenceSpecification); if(referencePoint == null) { referencePoint = lifelinePart.getFigure().getBounds().getCenter().getCopy(); } referencePoint.y = yLocation; return referencePoint; } /** * Get the command to reconnect general ordering attached to a moved occurrence specification * * @param movedOccurrenceSpecification * moving occurrence specification * @param yLocation * y location where occurrence specification is moved * @param lifelinePart * lifeline edit part containing the moved element * @param notToMoveEditParts * list of edit parts which must not be moved in the created command * @return command to reconnect general ordering edit parts linked to the occurrence specification or null */ private static Command getReconnectGeneralOrderingCommand(OccurrenceSpecification movedOccurrenceSpecification, int yLocation, LifelineEditPart lifelinePart, List<EditPart> notToMoveEditParts) { // the global command which shall be completed and returned CompoundCommand command = new CompoundCommand(); Point referencePoint = getReferencePoint(lifelinePart, movedOccurrenceSpecification, yLocation); EditPart childToReconnectTo = SequenceUtil.findPartToReconnectTo(lifelinePart, referencePoint); // if referencePoint is on a moved part, it must be translated with the location delta of this part if(!notToMoveEditParts.isEmpty() && childToReconnectTo != lifelinePart) { Point oldLoc = SequenceUtil.findLocationOfEvent(lifelinePart, movedOccurrenceSpecification); referencePoint.y = oldLoc.y; } // reconnect general ordering from the event for(GeneralOrdering go : movedOccurrenceSpecification.getToAfters()) { Collection<Setting> settings = CacheAdapter.INSTANCE.getNonNavigableInverseReferences(go); for(Setting ref : settings) { if(NotationPackage.eINSTANCE.getView_Element().equals(ref.getEStructuralFeature())) { View view = (View)ref.getEObject(); EditPart part = DiagramEditPartsUtil.getEditPartFromView(view, lifelinePart); // the general ordering part must start or finish on the lifeline (with the event) if(part instanceof ConnectionEditPart && !notToMoveEditParts.contains(part)) { Request reconnectRequest = makeReconnectRequest((ConnectionEditPart)part, true, referencePoint, childToReconnectTo); Command reconnect = childToReconnectTo.getCommand(reconnectRequest); if(reconnect.canExecute()) { command.add(reconnect); } } } } } // reconnect general ordering to the event for(GeneralOrdering go : movedOccurrenceSpecification.getToBefores()) { Collection<Setting> settings = CacheAdapter.INSTANCE.getNonNavigableInverseReferences(go); for(Setting ref : settings) { if(NotationPackage.eINSTANCE.getView_Element().equals(ref.getEStructuralFeature())) { View view = (View)ref.getEObject(); EditPart part = DiagramEditPartsUtil.getEditPartFromView(view, lifelinePart); // the general ordering part must start or finish on the lifeline (with the event) if(part instanceof ConnectionEditPart && !notToMoveEditParts.contains(part)) { Request reconnectRequest = makeReconnectRequest((ConnectionEditPart)part, false, referencePoint, childToReconnectTo); Command reconnect = childToReconnectTo.getCommand(reconnectRequest); if(reconnect.canExecute()) { command.add(reconnect); } } } } } // return null rather than an empty non executable command if(command.isEmpty()) { return null; } return command; } /** * Get the command to reconnect message attached to a moved occurrence specification * * @param movedOccurrenceSpecification * moving occurrence specification * @param yLocation * y location where occurrence specification is moved * @param lifelinePart * lifeline edit part containing the moved element * @param notToMoveEditParts * list of edit parts which must not be moved in the created command * @return command to reconnect message edit part linked to the occurrence specification or null */ private static Command getReconnectMessageCommand(OccurrenceSpecification movedOccurrenceSpecification, int yLocation, LifelineEditPart lifelinePart, List<EditPart> notToMoveEditParts) { // the global command which shall be completed and returned CompoundCommand command = new CompoundCommand(); if(movedOccurrenceSpecification instanceof MessageOccurrenceSpecification) { Point referencePoint = getReferencePoint(lifelinePart, movedOccurrenceSpecification, yLocation); EditPart childToReconnectTo = SequenceUtil.findPartToReconnectTo(lifelinePart, referencePoint); // reconnect message from the event Message message = ((MessageOccurrenceSpecification)movedOccurrenceSpecification).getMessage(); if(message != null && movedOccurrenceSpecification.equals(message.getSendEvent())) { Collection<Setting> settings = CacheAdapter.INSTANCE.getNonNavigableInverseReferences(message); for(Setting ref : settings) { if(NotationPackage.eINSTANCE.getView_Element().equals(ref.getEStructuralFeature())) { View view = (View)ref.getEObject(); EditPart part = DiagramEditPartsUtil.getEditPartFromView(view, lifelinePart); // the message part must start or finish on the lifeline (with the event) if(part instanceof ConnectionEditPart && !notToMoveEditParts.contains(part)) { Request reconnectRequest = makeReconnectRequest((ConnectionEditPart)part, true, referencePoint, childToReconnectTo); Command reconnect = childToReconnectTo.getCommand(reconnectRequest); command.add(reconnect); // update enclosing interaction fragment Command updateIFrag = SequenceUtil.createUpdateEnclosingInteractionCommand((MessageOccurrenceSpecification)movedOccurrenceSpecification, referencePoint, lifelinePart); if(updateIFrag != null && updateIFrag.canExecute()) { command.add(updateIFrag); } } } } } // reconnect message to the event if(message != null && movedOccurrenceSpecification.equals(message.getReceiveEvent())) { Collection<Setting> settings = CacheAdapter.INSTANCE.getNonNavigableInverseReferences(message); for(Setting ref : settings) { if(NotationPackage.eINSTANCE.getView_Element().equals(ref.getEStructuralFeature())) { View view = (View)ref.getEObject(); EditPart part = DiagramEditPartsUtil.getEditPartFromView(view, lifelinePart); // the message part must start or finish on the lifeline (with the event) if(part instanceof ConnectionEditPart && !notToMoveEditParts.contains(part)) { Request reconnectRequest = makeReconnectRequest((ConnectionEditPart)part, false, referencePoint, childToReconnectTo); Command reconnect = childToReconnectTo.getCommand(reconnectRequest); command.add(reconnect); // update enclosing interaction fragment Command updateIFrag = SequenceUtil.createUpdateEnclosingInteractionCommand((MessageOccurrenceSpecification)movedOccurrenceSpecification, referencePoint, lifelinePart); if(updateIFrag != null && updateIFrag.canExecute()) { command.add(updateIFrag); } } } } } } // return null rather than an empty non executable command if(command.isEmpty()) { return null; } return command; } /** * Get the command to move time/duration observations/constraints attached to a moved occurrence specification * * @param movedOccurrenceSpecification1 * first moved occurrence specification * @param movedOccurrenceSpecification2 * second moved occurrence specification (or null) * @param yLocation1 * y location where first occurrence specification is moved * @param yLocation2 * y location where second occurrence specification is moved (or -1) * @param lifelinePart * lifeline edit part containing the moved element * @param notToMoveEditParts * list of edit parts which must not be moved in the created command * @return command to move time edit parts linked to the occurrence specification or null */ private static Command getMoveTimeElementsCommand(OccurrenceSpecification movedOccurrenceSpecification1, OccurrenceSpecification movedOccurrenceSpecification2, int yLocation1, int yLocation2, LifelineEditPart lifelinePart, List<EditPart> notToMoveEditParts) { // the global command which shall be completed and returned CompoundCommand globalCmd = new CompoundCommand(); IFigure lifelineFigure = lifelinePart.getFigure(); // relocate each linked time element contained within the lifeline part for(Object lifelineChild : lifelinePart.getChildren()) { if(lifelineChild instanceof IBorderItemEditPart && !notToMoveEditParts.contains(lifelineChild)) { final IBorderItemEditPart timePart = (IBorderItemEditPart)lifelineChild; Command cmd = getMoveSingleTimeRelatedElementCommand(timePart, movedOccurrenceSpecification1, movedOccurrenceSpecification2, yLocation1, yLocation2, lifelinePart); if(cmd != null) { globalCmd.add(cmd); } } } // relocate each observation linked time element for(Object targetConnection : lifelinePart.getTargetConnections()){ if(targetConnection instanceof ObservationLinkEditPart){ Command cmd = getMoveSingleTimeRelatedElementCommand((ObservationLinkEditPart)targetConnection, movedOccurrenceSpecification1, movedOccurrenceSpecification2, yLocation1, yLocation2, lifelinePart); if(cmd != null) { globalCmd.add(cmd); } } } // refresh layout commands : // one before the commands for the undo and one after for classic execution if(!globalCmd.isEmpty() && lifelineFigure instanceof BorderedNodeFigure) { Command relayout = getReLayoutCmd((BorderedNodeFigure)lifelineFigure, false); Command relayoutUndo = getReLayoutCmd((BorderedNodeFigure)lifelineFigure, true); if(relayout != null && relayoutUndo != null) { CompoundCommand commandWithRelayout = new CompoundCommand(); commandWithRelayout.add(relayoutUndo); commandWithRelayout.add(globalCmd); commandWithRelayout.add(relayout); return commandWithRelayout; } } // return null rather than an empty non executable command if(globalCmd.isEmpty()) { return null; } return globalCmd; } private static Command getMoveSingleTimeRelatedElementCommand( final ObservationLinkEditPart targetConnection, final OccurrenceSpecification movedOccurrenceSpecification1, final OccurrenceSpecification movedOccurrenceSpecification2, final int yLocation1, final int yLocation2,final LifelineEditPart lifelinePart) { AbstractTransactionalCommand updateTargetAnchorCommand = new AbstractTransactionalCommand(((IGraphicalEditPart) targetConnection).getEditingDomain(),"update target anchor",null) { @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { // both bounds may have changed Point referencePoint1 = getReferencePoint(lifelinePart, movedOccurrenceSpecification1, yLocation1); Point referencePoint2 = getReferencePoint(lifelinePart, movedOccurrenceSpecification2, yLocation2); int position1 = PositionConstants.NONE; int position2 = PositionConstants.NONE; TimeObservationLabelEditPart tolEP = (TimeObservationLabelEditPart)targetConnection.getSource(); if(tolEP == null){ return CommandResult.newCancelledCommandResult(); } if(movedOccurrenceSpecification1 != null) { position1 = SequenceUtil.positionWhereEventIsLinkedToPart(movedOccurrenceSpecification1, tolEP); } if(movedOccurrenceSpecification2 != null) { position2 = SequenceUtil.positionWhereEventIsLinkedToPart(movedOccurrenceSpecification2, tolEP); } ConnectionAnchor targetAnchor = null; if(position1 == PositionConstants.CENTER){ targetAnchor = lifelinePart.getNodeFigure().getSourceConnectionAnchorAt(referencePoint1); }else if(position2 == PositionConstants.CENTER){ targetAnchor = lifelinePart.getNodeFigure().getSourceConnectionAnchorAt(referencePoint2); } if(targetAnchor!= null){ String newTargetTerminal = lifelinePart.mapConnectionAnchorToTerminal(targetAnchor); ConnectorImpl c = (ConnectorImpl)targetConnection.getModel(); if (newTargetTerminal != null) { if (newTargetTerminal.length() == 0) c.setTargetAnchor(null); else { IdentityAnchor a = (IdentityAnchor) c.getTargetAnchor(); if (a == null) a = NotationFactory.eINSTANCE.createIdentityAnchor(); a.setId(newTargetTerminal); c.setTargetAnchor(a); } } } return CommandResult.newOKCommandResult(); } }; // return the resize command ICommandProxy resize = new ICommandProxy(updateTargetAnchorCommand); return resize; } /** * Get a command to move the time related element's edit part * * @param timePart * time related element's edit part to move * @param movedOccurrenceSpecification1 * first moved occurrence specification * @param movedOccurrenceSpecification2 * second moved occurrence specification (or null) * @param yLocation1 * y location where first occurrence specification is moved * @param yLocation2 * y location where second occurrence specification is moved (or -1) * @param lifelinePart * lifeline edit part containing the moved element * @return */ private static Command getMoveSingleTimeRelatedElementCommand(IBorderItemEditPart timePart, OccurrenceSpecification movedOccurrenceSpecification1, OccurrenceSpecification movedOccurrenceSpecification2, int yLocation1, int yLocation2, LifelineEditPart lifelinePart) { IFigure lifelineFigure = lifelinePart.getFigure(); // get positions where edit part is attached to events int position1 = PositionConstants.NONE; int position2 = PositionConstants.NONE; if(movedOccurrenceSpecification1 != null) { position1 = SequenceUtil.positionWhereEventIsLinkedToPart(movedOccurrenceSpecification1, timePart); } if(movedOccurrenceSpecification2 != null) { position2 = SequenceUtil.positionWhereEventIsLinkedToPart(movedOccurrenceSpecification2, timePart); } // move necessary bounds Rectangle newBounds = null; if(position1 != PositionConstants.NONE && position2 != PositionConstants.NONE) { // both bounds may have changed Point referencePoint1 = getReferencePoint(lifelinePart, movedOccurrenceSpecification1, yLocation1); Point referencePoint2 = getReferencePoint(lifelinePart, movedOccurrenceSpecification2, yLocation2); makeRelativeToLifeline(referencePoint1, lifelinePart, false); makeRelativeToLifeline(referencePoint2, lifelinePart, false); // Get old bounds information by consulting old figure int oldY = timePart.getFigure().getBounds().getLocation().y - lifelineFigure.getBounds().getLocation().y; int oldHeight = timePart.getFigure().getSize().height; // Compute new bounds of the time element if(position1 == PositionConstants.CENTER || position2 == PositionConstants.CENTER) { // should not happen, except if both events are merged at the same location newBounds = new Rectangle(referencePoint1.x, referencePoint1.y - oldHeight / 2, -1, oldHeight); } else { int top = oldY; int bottom = oldY + oldHeight; // bound is based on two events. Recompute it according to moved event(s). if(position1 == PositionConstants.TOP) { top = referencePoint1.y; } else if(position1 == PositionConstants.BOTTOM) { bottom = referencePoint1.y; } if(position2 == PositionConstants.TOP) { top = referencePoint2.y; } else if(position2 == PositionConstants.BOTTOM) { bottom = referencePoint2.y; } // top and bottom may have been inverted during the move. // restore x position, fix time duration always move to east int viewX = (Integer) ViewUtil.getPropertyValue((View) timePart.getModel(), NotationPackage.eINSTANCE .getLocation_X(), NotationPackage.eINSTANCE.getLocation_X().getEContainingClass()); newBounds = new Rectangle(viewX, Math.min(top, bottom), -1, Math.abs(bottom - top)); // newBounds = new Rectangle(referencePoint1.x, Math.min(top, bottom), -1, Math.abs(bottom - top)); } } else if(position1 != PositionConstants.NONE) { Point referencePoint1 = getReferencePoint(lifelinePart, movedOccurrenceSpecification1, yLocation1); makeRelativeToLifeline(referencePoint1, lifelinePart, false); // Get old bounds information by consulting old figure int oldY = timePart.getFigure().getBounds().getLocation().y - lifelineFigure.getBounds().getLocation().y; int oldHeight = timePart.getFigure().getSize().height; // Compute new bounds of the time element if(position1 == PositionConstants.CENTER) { newBounds = new Rectangle(referencePoint1.x, referencePoint1.y - oldHeight / 2, -1, oldHeight); } else { int top = oldY; int bottom = oldY + oldHeight; // bound is based on two events. Recompute it according to moved event(s). if(position1 == PositionConstants.TOP) { top = referencePoint1.y; } else if(position1 == PositionConstants.BOTTOM) { bottom = referencePoint1.y; } // top and bottom may have been inverted during the move. newBounds = new Rectangle(referencePoint1.x, Math.min(top, bottom), -1, Math.abs(bottom - top)); } } else if(position2 != PositionConstants.NONE) { Point referencePoint2 = getReferencePoint(lifelinePart, movedOccurrenceSpecification2, yLocation2); makeRelativeToLifeline(referencePoint2, lifelinePart, false); // Get old bounds information by consulting old figure int oldY = timePart.getFigure().getBounds().getLocation().y - lifelineFigure.getBounds().getLocation().y; int oldHeight = timePart.getFigure().getSize().height; // Compute new bounds of the time element if(position2 == PositionConstants.CENTER) { newBounds = new Rectangle(referencePoint2.x, referencePoint2.y - oldHeight / 2, -1, oldHeight); } else { int top = oldY; int bottom = oldY + oldHeight; // bound is based on two events. Recompute it according to moved event(s). if(position2 == PositionConstants.TOP) { top = referencePoint2.y; } else if(position2 == PositionConstants.BOTTOM) { bottom = referencePoint2.y; } // top and bottom may have been inverted during the move. newBounds = new Rectangle(referencePoint2.x, Math.min(top, bottom), -1, Math.abs(bottom - top)); } } if(newBounds != null) { TransactionalEditingDomain editingDomain = timePart.getEditingDomain(); // return the resize command ICommandProxy resize = new ICommandProxy(new SetBoundsCommand(editingDomain, DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter((View)timePart.getModel()), newBounds)); return resize; } return null; } /** * Make an absolute point relative to a lifeline figure. * * @param absolutePoint * the absolute point to translate * @param lifelinePart * the containing lifeline edit part */ private static void makeRelativeToLifeline(Point absolutePoint, LifelineEditPart lifelinePart, boolean relativeToContentPane) { IFigure figure; if(relativeToContentPane) { figure = lifelinePart.getContentPane(); } else { figure = lifelinePart.getFigure(); } figure.translateToRelative(absolutePoint); absolutePoint.translate(figure.getBounds().getLocation().getNegated()); } /** * Get the command to move execution specification(s) attached to moved occurrence specification(s) * * @param movedOccurrenceSpecification1 * first moved occurrence specification * @param movedOccurrenceSpecification2 * second moved occurrence specification (or null) * @param yLocation1 * y location where first occurrence specification is moved * @param yLocation2 * y location where second occurrence specification is moved (or -1) * @param lifelinePart * lifeline edit part containing the moved element * @param notToMoveEditParts * list of edit parts which must not be moved in the created command * @return command to move execution specification edit part linked to the occurrence specification or null */ private static Command getMoveExecutionSpecificationCommand(OccurrenceSpecification movedOccurrenceSpecification1, OccurrenceSpecification movedOccurrenceSpecification2, int yLocation1, int yLocation2, LifelineEditPart lifelinePart, List<EditPart> notToMoveEditParts) { // the global command which shall be completed and returned CompoundCommand globalCmd = new CompoundCommand(); // execution(s) linked to the event must be resized EditPart node1 = null; if(movedOccurrenceSpecification1 != null) { node1 = SequenceUtil.getLinkedEditPart(lifelinePart, movedOccurrenceSpecification1); } EditPart node2 = null; if(movedOccurrenceSpecification2 != null) { node2 = SequenceUtil.getLinkedEditPart(lifelinePart, movedOccurrenceSpecification2); } if(node1 instanceof GraphicalEditPart && !notToMoveEditParts.contains(node1)) { Command cmd = getMoveSingleExecutionSpecificationCommand((GraphicalEditPart)node1, movedOccurrenceSpecification1, movedOccurrenceSpecification2, yLocation1, yLocation2, lifelinePart); if(cmd != null) { globalCmd.add(cmd); } } if(node2 != node1 && node2 instanceof GraphicalEditPart && !notToMoveEditParts.contains(node2)) { Command cmd = getMoveSingleExecutionSpecificationCommand((GraphicalEditPart)node2, movedOccurrenceSpecification2, null, yLocation2, -1, lifelinePart); if(cmd != null) { globalCmd.add(cmd); } } // return null rather than an empty non executable command if(globalCmd.isEmpty()) { return null; } return globalCmd; } /** * Get the command to move an execution specification attached to moved occurrence specification(s) * * @param executionSpecificationPart * the execution specification edit part to move * @param movedOccurrenceSpecification1 * first moved occurrence specification * @param movedOccurrenceSpecification2 * second moved occurrence specification (or null) * @param yLocation1 * y location where first occurrence specification is moved * @param yLocation2 * y location where second occurrence specification is moved (or -1) * @param lifelinePart * lifeline edit part containing the moved element * @return command to move the execution specification edit part or null */ private static Command getMoveSingleExecutionSpecificationCommand(GraphicalEditPart executionSpecificationPart, OccurrenceSpecification movedOccurrenceSpecification1, OccurrenceSpecification movedOccurrenceSpecification2, int yLocation1, int yLocation2, LifelineEditPart lifelinePart) { // execution linked to the event must be resized EObject execution = executionSpecificationPart.resolveSemanticElement(); if(execution instanceof ExecutionSpecification) { // finish or start events of the execution have been moved // get positions where execution edit part is attached to events int position1 = PositionConstants.NONE; int position2 = PositionConstants.NONE; OccurrenceSpecification start = ((ExecutionSpecification)execution).getStart(); OccurrenceSpecification finish = ((ExecutionSpecification)execution).getFinish(); if(start != null && start.equals(movedOccurrenceSpecification1)) { position1 = PositionConstants.TOP; } else if(finish != null && finish.equals(movedOccurrenceSpecification1)) { position1 = PositionConstants.BOTTOM; } if(start != null && start.equals(movedOccurrenceSpecification2)) { position2 = PositionConstants.TOP; } else if(finish != null && finish.equals(movedOccurrenceSpecification2)) { position2 = PositionConstants.BOTTOM; } // move necessary bounds Rectangle newBounds = null; int heighDelta = 0; if(position1 != PositionConstants.NONE && position2 != PositionConstants.NONE) { // both bounds have changed Point referencePoint1 = getReferencePoint(lifelinePart, movedOccurrenceSpecification1, yLocation1); Point referencePoint2 = getReferencePoint(lifelinePart, movedOccurrenceSpecification2, yLocation2); makeRelativeToLifeline(referencePoint1, lifelinePart, true); makeRelativeToLifeline(referencePoint2, lifelinePart, true); // Get old bounds information by consulting old figure Rectangle esBounds = SequenceUtil.getAbsoluteBounds(executionSpecificationPart); Point esLoc = esBounds.getLocation(); makeRelativeToLifeline(esLoc, lifelinePart, true); esBounds.setLocation(esLoc); int oldX = esBounds.x; int oldY = esBounds.y; int oldWidth = esBounds.width; int oldHeight = esBounds.height; // Compute new bounds of the time element int top = oldY; int bottom = oldY + oldHeight; // bound is based on two events. Recompute it according to moved event(s). if(position1 == PositionConstants.TOP) { top = referencePoint1.y; } else if(position1 == PositionConstants.BOTTOM) { bottom = referencePoint1.y; } if(position2 == PositionConstants.TOP) { top = referencePoint2.y; } else if(position2 == PositionConstants.BOTTOM) { bottom = referencePoint2.y; } // top and bottom may have been inverted during the move. newBounds = new Rectangle(oldX, Math.min(top, bottom), oldWidth, Math.abs(bottom - top)); } else if(position1 != PositionConstants.NONE) { Point referencePoint1 = getReferencePoint(lifelinePart, movedOccurrenceSpecification1, yLocation1); makeRelativeToLifeline(referencePoint1, lifelinePart, true); // Get old bounds information by consulting old figure Rectangle esBounds = SequenceUtil.getAbsoluteBounds(executionSpecificationPart); Point esLoc = esBounds.getLocation(); makeRelativeToLifeline(esLoc, lifelinePart, true); esBounds.setLocation(esLoc); int oldX = esBounds.x; int oldY = esBounds.y; int oldWidth = esBounds.width; int oldHeight = esBounds.height; // Compute new bounds of the time element int top = oldY; int bottom = oldY + oldHeight; // bound is based on two events. Recompute it according to moved event(s). if(position1 == PositionConstants.TOP) { top = referencePoint1.y; } else if(position1 == PositionConstants.BOTTOM) { bottom = referencePoint1.y; } // top and bottom may have been inverted during the move. newBounds = new Rectangle(oldX, Math.min(top, bottom), oldWidth, Math.abs(bottom - top)); } else if(position2 != PositionConstants.NONE) { Point referencePoint2 = getReferencePoint(lifelinePart, movedOccurrenceSpecification2, yLocation2); makeRelativeToLifeline(referencePoint2, lifelinePart, true); // Get old bounds information by consulting old figure Rectangle esBounds = SequenceUtil.getAbsoluteBounds(executionSpecificationPart); Point esLoc = esBounds.getLocation(); makeRelativeToLifeline(esLoc, lifelinePart, true); esBounds.setLocation(esLoc); int oldX = esBounds.x; int oldY = esBounds.y; int oldWidth = esBounds.width; int oldHeight = esBounds.height; // Compute new bounds of the time element int top = oldY; int bottom = oldY + oldHeight; // bound is based on two events. Recompute it according to moved event(s). if(position2 == PositionConstants.TOP) { top = referencePoint2.y; } else if(position2 == PositionConstants.BOTTOM) { bottom = referencePoint2.y; } // top and bottom may have been inverted during the move. newBounds = new Rectangle(oldX, Math.min(top, bottom), oldWidth, Math.abs(bottom - top)); } if(newBounds != null) { // adjust bounds for execution specification newBounds.height -= heighDelta; TransactionalEditingDomain editingDomain = executionSpecificationPart.getEditingDomain(); // return the resize command ICommandProxy resize = new ICommandProxy(new SetBoundsCommand(editingDomain, DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter((View)executionSpecificationPart.getModel()), newBounds)); return resize; } } return null; } /** * Chain the commands to move associated parts when a connection end is reconnected. * * @param command * existing reconnection command * @param request * the reconnection request * @param connectableNode * the node edit part connected to the moved connection * @return the completed command */ public static Command completeReconnectConnectionCommand(Command command, ReconnectRequest request, INodeEditPart connectableNode) { if(chainEffectIsDisabled(request)) { return command; } CompoundCommand globalCmd = new CompoundCommand(); globalCmd.add(command); List<EditPart> notToMoveEditParts = new ArrayList<EditPart>(1); notToMoveEditParts.add(request.getConnectionEditPart()); // move time related elements linked with the event LifelineEditPart lifelinePart = SequenceUtil.getParentLifelinePart(connectableNode); MessageEnd event = getMessageEndFromReconnectMessage(request); if(event instanceof OccurrenceSpecification) { Command cmd = getMoveOccurrenceSpecificationsCommand((OccurrenceSpecification)event, null, request.getLocation().y, -1, lifelinePart, notToMoveEditParts); if(cmd != null) { globalCmd.add(cmd); } } OccurrenceSpecification event2 = getOccurrenceSpecificationFromReconnectGeneralOrdering(request); if(event2 instanceof OccurrenceSpecification) { Command cmd = getMoveOccurrenceSpecificationsCommand((OccurrenceSpecification)event2, null, request.getLocation().y, -1, lifelinePart, notToMoveEditParts); if(cmd != null) { globalCmd.add(cmd); } } return globalCmd; } /** * Check if moving chain effect has been disabled to avoid an infinite loop. * * @param request * the request wich initiated the move * @return true if no additional command must be performed. */ private static boolean chainEffectIsDisabled(Request request) { Object doNotToMoveEditParts = request.getExtendedData().get(SequenceRequestConstant.DO_NOT_MOVE_EDIT_PARTS); return Boolean.TRUE.equals(doNotToMoveEditParts); } /** * Complete a command to move time/duration constraints/observation which are linked to the moved edit part * * @param compoundCmd * existing command to complete * @param executionSpecificationEP * the moved edit part representing an execution specification * @param newBounds * the new part's bounds (relative to the figure's parent) * @param request * the change bounds request which originated this move * @return the updated parameter compoundCmd for convenience */ public static CompoundCommand completeMoveExecutionSpecificationCommand(CompoundCommand compoundCmd, ShapeNodeEditPart executionSpecificationEP, Rectangle newBounds, ChangeBoundsRequest request) { if(chainEffectIsDisabled(request)) { return compoundCmd; } // Move events delimiting the ExecutionSpecification EObject execSpec = executionSpecificationEP.resolveSemanticElement(); if(execSpec instanceof ExecutionSpecification) { LifelineEditPart lifelinePart = SequenceUtil.getParentLifelinePart(executionSpecificationEP); // first, get absolute bounds newBounds = newBounds.getCopy(); IFigure parentFig = executionSpecificationEP.getFigure().getParent(); parentFig.translateToAbsolute(newBounds); newBounds.translate(parentFig.getBounds().getLocation()); // move start and finish events OccurrenceSpecification start = ((ExecutionSpecification)execSpec).getStart(); int startY = newBounds.getTop().y; OccurrenceSpecification finish = ((ExecutionSpecification)execSpec).getFinish(); int finishY = newBounds.getBottom().y; List<EditPart> notToMoveEditParts = new ArrayList<EditPart>(1); notToMoveEditParts.add(executionSpecificationEP); Command cmd = getMoveOccurrenceSpecificationsCommand(start, finish, startY, finishY, lifelinePart, notToMoveEditParts); if(cmd != null) { compoundCmd.add(cmd); } if(request.getSizeDelta().height == 0) { // move time elements for events between start and finish InteractionFragment nextOccSpec = InteractionFragmentHelper.findNextFragment(start, start.eContainer()); while(nextOccSpec != null && nextOccSpec != finish) { Point occSpecLocation = SequenceUtil.findLocationOfEvent(lifelinePart, nextOccSpec); if(nextOccSpec instanceof OccurrenceSpecification && occSpecLocation != null) { int occSpecY = occSpecLocation.y + request.getMoveDelta().y; cmd = getMoveTimeElementsCommand((OccurrenceSpecification)nextOccSpec, null, occSpecY, -1, lifelinePart, notToMoveEditParts); if(cmd != null) { compoundCmd.add(cmd); } } nextOccSpec = InteractionFragmentHelper.findNextFragment(nextOccSpec, start.eContainer()); } } } return compoundCmd; } /** * Prepare a request which is supposed to move a time/duration constraints/observation edit part. * The request will be updated if some operations are forbidden. * * @param request * the move request * @param movedTimePart * the moved time/duration constraints/observation edit part. */ public static void prepareTimeRelatedElementMoveRequest(ChangeBoundsRequest request, IBorderItemEditPart movedTimePart) { // Erase the y move if element can not be moved on y axe if(!canTimeElementPartBeYMoved(movedTimePart)) { request.getMoveDelta().y = 0; } } /** * Complete the command to move an edit part representing a time/duration constraints/observation. * * @param moveCommand * the move command to complete with chaining * @param request * the request which initiated the move * @param hostFigure * figure which is being moved * @param hostEditPart * edit part which is being moved * @return the complete command. */ public static Command completeMoveTimeRelatedElementCommand(Command moveCommand, ChangeBoundsRequest request, EditPart hostEditPart, IFigure hostFigure) { if(chainEffectIsDisabled(request)) { return moveCommand; } Rectangle bounds = request.getTransformedRectangle(hostFigure.getBounds()); hostFigure.getParent().translateToAbsolute(bounds); LifelineEditPart lifelinePart = SequenceUtil.getParentLifelinePart(hostEditPart); if(lifelinePart != null && hostEditPart instanceof IBorderItemEditPart) { IBorderItemEditPart timeElementEditPart = (IBorderItemEditPart)hostEditPart; EObject timeElement = timeElementEditPart.resolveSemanticElement(); OccurrenceSpecification occSpec1 = null; int yLocation1 = -1; OccurrenceSpecification occSpec2 = null; int yLocation2 = -1; // find occurrence specifications of the time element if(timeElement instanceof TimeConstraint) { Iterator<Element> it = ((TimeConstraint)timeElement).getConstrainedElements().iterator(); while(it.hasNext() && occSpec1 == null) { Element elem = it.next(); if(elem instanceof OccurrenceSpecification) { int position1 = whereEventIsLinked((OccurrenceSpecification)elem, timeElementEditPart); if(position1 != PositionConstants.NONE) { occSpec1 = (OccurrenceSpecification)elem; yLocation1 = getLocation(bounds, position1).y; } } } } else if(timeElement instanceof TimeObservation) { NamedElement event = ((TimeObservation)timeElement).getEvent(); if(event instanceof OccurrenceSpecification) { int position1 = whereEventIsLinked((OccurrenceSpecification)event, timeElementEditPart); if(position1 != PositionConstants.NONE) { occSpec1 = (OccurrenceSpecification)event; yLocation1 = getLocation(bounds, position1).y; } } } else if(timeElement instanceof DurationConstraint) { Iterator<Element> it = ((DurationConstraint)timeElement).getConstrainedElements().iterator(); while(it.hasNext() && (occSpec1 == null || occSpec2 == null)) { Element elem = it.next(); if(elem instanceof OccurrenceSpecification && occSpec1 != null) { int position2 = whereEventIsLinked((OccurrenceSpecification)elem, timeElementEditPart); if(position2 != PositionConstants.NONE) { occSpec2 = (OccurrenceSpecification)elem; yLocation2 = getLocation(bounds, position2).y; } } else if(elem instanceof OccurrenceSpecification) { int position1 = whereEventIsLinked((OccurrenceSpecification)elem, timeElementEditPart); if(position1 != PositionConstants.NONE) { occSpec1 = (OccurrenceSpecification)elem; yLocation1 = getLocation(bounds, position1).y; } } } } if(occSpec1 != null) { List<EditPart> notToMoveEditParts = Collections.singletonList(hostEditPart); Command cmd = getMoveOccurrenceSpecificationsCommand(occSpec1, occSpec2, yLocation1, yLocation2, lifelinePart, notToMoveEditParts); if(cmd != null) { return moveCommand.chain(cmd); } } } return null; } /** * Make the request to reconnect the connection * * @param connection * connection part * @param isSource * true if the source must be reconnect, false for target * @param location * the location where to reconnect * @param partToReconnectTo * the part which the connection must be reconnected to (or null if unknown or of no importance) * @return the reconnection request */ @SuppressWarnings("unchecked") private static ReconnectRequest makeReconnectRequest(ConnectionEditPart connection, boolean isSource, Point location, EditPart partToReconnectTo) { // Obtain the target edit part EditPart targetEP = partToReconnectTo; String type; if(isSource) { type = RequestConstants.REQ_RECONNECT_SOURCE; if(targetEP == null) { targetEP = connection.getSource(); } } else { type = RequestConstants.REQ_RECONNECT_TARGET; if(targetEP == null) { targetEP = connection.getTarget(); } } // Create and set the properties of the request ReconnectRequest reconnReq = new ReconnectRequest(); reconnReq.setConnectionEditPart(connection); reconnReq.setLocation(location); reconnReq.setTargetEditPart(targetEP); reconnReq.setType(type); // add a parameter to bypass the move impact to avoid infinite loop reconnReq.getExtendedData().put(SequenceRequestConstant.DO_NOT_MOVE_EDIT_PARTS, true); // Return the request return reconnReq; } /** * Get the location on the bounds * * @param bounds * the rectangle bounds * @param position * one of {@link PositionConstants#TOP}, {@link PositionConstants#CENTER}, {@link PositionConstants#BOTTOM} * @return the point at the given position or null if position is incorrect */ private static Point getLocation(Rectangle bounds, int position) { if(position == PositionConstants.TOP) { return bounds.getTop(); } else if(position == PositionConstants.CENTER) { return bounds.getCenter(); } else if(position == PositionConstants.BOTTOM) { return bounds.getBottom(); } return null; } /** * The position of the host where the event is linked * * @param event * the occurrence specification * @param hostEditPart * the host edit part which is linked to the occurrence specification * @return one of {@link PositionConstants#TOP}, {@link PositionConstants#CENTER}, {@link PositionConstants#BOTTOM}, * {@link PositionConstants#NONE} */ private static int whereEventIsLinked(OccurrenceSpecification event, EditPart hostEditPart) { if(hostEditPart instanceof IBorderItemEditPart) { return SequenceUtil.positionWhereEventIsLinkedToPart(event, (IBorderItemEditPart)hostEditPart); } return PositionConstants.NONE; } /** * Get the occurrence specification which correspond to the moved general ordering end * * @param request * the general odering reconnection request * @return moved OccurrenceSpecification or null */ private static OccurrenceSpecification getOccurrenceSpecificationFromReconnectGeneralOrdering(ReconnectRequest request) { if(request.getConnectionEditPart() instanceof ConnectionEditPart) { EObject generalOrdering = ((ConnectionEditPart)request.getConnectionEditPart()).resolveSemanticElement(); if(generalOrdering instanceof GeneralOrdering) { if(RequestConstants.REQ_RECONNECT_SOURCE.equals(request.getType())) { return ((GeneralOrdering)generalOrdering).getBefore(); } else if(RequestConstants.REQ_RECONNECT_TARGET.equals(request.getType())) { return ((GeneralOrdering)generalOrdering).getAfter(); } } } return null; } /** * Get the message end which correspond to the moved message end * * @param request * the message reconnection request * @return moved MessageEnd or null */ private static MessageEnd getMessageEndFromReconnectMessage(ReconnectRequest request) { if(request.getConnectionEditPart() instanceof ConnectionEditPart) { EObject message = ((ConnectionEditPart)request.getConnectionEditPart()).resolveSemanticElement(); if(message instanceof Message) { if(RequestConstants.REQ_RECONNECT_SOURCE.equals(request.getType())) { return ((Message)message).getSendEvent(); } else if(RequestConstants.REQ_RECONNECT_TARGET.equals(request.getType())) { return ((Message)message).getReceiveEvent(); } } } return null; } /** * Know whether this time element part can be moved within the lifeline or not. * Parts linked with a destruction event can not be moved since the destruction event is always at the end. * * @param timeElementPart * the part representing a time/duration constraint/observation * @return true if the part can be moved */ public static boolean canTimeElementPartBeYMoved(IBorderItemEditPart timeElementPart) { EObject timeElement = timeElementPart.resolveSemanticElement(); List<? extends Element> occurrences = Collections.emptyList(); if(timeElement instanceof TimeObservation) { NamedElement occurence = ((TimeObservation)timeElement).getEvent(); occurrences = Collections.singletonList(occurence); } else if(timeElement instanceof TimeConstraint || timeElement instanceof DurationConstraint) { occurrences = ((IntervalConstraint)timeElement).getConstrainedElements(); } // check whether one of the time occurrences correspond to a DestructionEvent for(Element occurrence : occurrences) { if(occurrence instanceof DestructionOccurrenceSpecification) { return false; } } return true; } /** * Get a command which refreshes the bordered layout of the node. * * @param node * the node figure with bordered items (including time-related parts) * @param onUndo * if true the relayout will be done on undo only, if false it will be done on classic execute only * @return the refresh command */ private static Command getReLayoutCmd(BorderedNodeFigure node, boolean onUndo) { // relayout the border container figure so that time elements are refreshed final IFigure container = node.getBorderItemContainer(); if(onUndo) { return new Command() { @Override public void undo() { container.getLayoutManager().layout(container); } }; } else { return new Command() { @Override public void execute() { container.getLayoutManager().layout(container); } }; } } }