Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui')
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/SequenceDiagramPlugin.java95
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramInterpretedExpressionSwitch.java268
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramTypeProvider.java434
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/EObjectQuery.java54
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/SequenceDiagramTemplateEdit.java98
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceCollapseUpdater.java147
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceToolInterpretedExpressionSwitch.java218
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/migration/SequenceDiagramRepresentationsFileMigrationParticipant.java229
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/refresh/VisibilityEventHandler.java89
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/api/SequenceDiagramLayout.java51
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceDelegatingCommandFactory.java384
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceEMFCommandFactory.java146
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ConnectionAnchorOperation.java209
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/EndOfLifeOperations.java172
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ExecutionOperations.java274
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/MoveViewOperation.java75
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeMessagesOperation.java66
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeViewOperation.java75
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/SequenceEditPartsOperations.java367
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftDescendantMessagesOperation.java269
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftMessagesOperation.java195
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/AbstractSequenceBorderedEditPart.java171
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentCompartmentEditPart.java113
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentEditPart.java119
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/EndOfLifeEditPart.java146
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ExecutionEditPart.java162
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ISequenceEventEditPart.java31
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InstanceRoleEditPart.java139
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InteractionUseEditPart.java264
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LifelineEditPart.java265
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LostMessageEndEditPart.java129
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ObservationPointEditPart.java282
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandCompartmentEditPart.java56
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandEditPart.java183
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceBracketEdgeEditPart.java52
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceDiagramEditPart.java252
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageEditPart.java220
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageNameEditPart.java86
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/StateEditPart.java77
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java273
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/CombinedFragmentResizableEditPolicy.java415
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/EndOfLifeSelectionPolicy.java228
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java696
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java336
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/FrameAwareContainerCreationPolicy.java276
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ISEComplexMoveCommandBuilder.java332
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleResizableEditPolicy.java316
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleSiriusGraphicalNodeEditPolicy.java306
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InteractionUseResizableEditPolicy.java120
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/LostMessageEndSelectionPolicy.java124
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ObservationPointSelectionPolicy.java76
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java337
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java333
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java194
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceLaunchToolEditPolicy.java73
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java852
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java245
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceSiriusGraphicalNodeEditPolicy.java258
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/StateSelectionEditPolicy.java120
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/tools/SequenceMessageSelectConnectionEditPartTracker.java108
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInstanceRoleValidator.java152
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java387
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractMessageCreationValidator.java107
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractNodeEventResizeSelectionValidator.java491
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java152
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractSequenceInteractionValidator.java150
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentMoveValidator.java95
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentResizeValidator.java106
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CreateMessageCreationValidator.java71
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DefaultMessageCreationValidator.java248
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DestroyMessageCreationValidator.java66
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/FrameCreationValidator.java493
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/ISEComplexMoveValidator.java633
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleGraphicalHorizontalOrderingComparator.java64
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleMoveValidator.java84
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleResizeValidator.java91
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseMoveValidator.java95
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseResizeValidator.java84
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/OperandResizeValidator.java49
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/PositionsChecker.java116
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/CombinedFragmentInvisibleResizableCompartmentFigure.java47
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/ExecutionItemLocator.java162
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/HorizontalGuide.java50
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/LifelineNodeFigure.java59
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/OperandFigure.java87
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/RangeGuide.java77
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceMessageLabelLocator.java79
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceNodeFigure.java115
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceSlidableAnchor.java100
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SouthCenteredBorderItemLocator.java100
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CenteredBorderItemLocator.java123
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CombinedFragmentVerticalPositionFunction.java61
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/InstanceUseVerticalPositionFunction.java60
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/LayoutEditPartConstants.java53
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceGraphicalHelper.java219
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceLayoutProvider.java87
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceMessagesRouter.java436
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceZOrderingRefresher.java108
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramEditPartProvider.java148
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramLayoutProvider.java61
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/CreateRequestQuery.java80
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/DelegatingDiagramCommandFactory.java331
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsHelper.java329
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsTreeIterator.java69
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/FinalParentHelper.java307
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/RequestQuery.java270
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/SequenceDiagramEPQuery.java41
107 files changed, 20073 insertions, 0 deletions
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/SequenceDiagramPlugin.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/SequenceDiagramPlugin.java
new file mode 100644
index 0000000000..cd6ffd4b4c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/SequenceDiagramPlugin.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException;
+
+/**
+ * The activator class controls the plug-in life cycle.
+ *
+ * @author pcdavid
+ */
+public class SequenceDiagramPlugin extends AbstractUIPlugin {
+ /**
+ * The plug-in ID.
+ */
+ public static final String PLUGIN_ID = "org.eclipse.sirius.diagram.sequence.ui";
+
+ /**
+ * The shared instance.
+ */
+ private static SequenceDiagramPlugin plugin;
+
+ /**
+ * The constructor.
+ */
+ public SequenceDiagramPlugin() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance.
+ *
+ * @return the shared instance.
+ */
+ public static SequenceDiagramPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Logs a warning.
+ *
+ * @param message
+ * the message.
+ * @param e
+ * the exception.
+ */
+ public void warning(String message, EvaluationException e) {
+ IStatus status = new Status(IStatus.WARNING, PLUGIN_ID, message, e);
+ getLog().log(status);
+ }
+
+ /**
+ * Logs an error.
+ *
+ * @param message
+ * the message.
+ * @param e
+ * the exception.
+ */
+ public void error(String message, EvaluationException e) {
+ IStatus status = new Status(IStatus.ERROR, PLUGIN_ID, message, e);
+ getLog().log(status);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramInterpretedExpressionSwitch.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramInterpretedExpressionSwitch.java
new file mode 100644
index 0000000000..e67faebedc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramInterpretedExpressionSwitch.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.api.diagramtype;
+
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionTargetSwitch;
+import org.eclipse.sirius.description.RepresentationDescription;
+import org.eclipse.sirius.description.RepresentationElementMapping;
+import org.eclipse.sirius.diagram.sequence.description.DelimitedEventMapping;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.description.FrameMapping;
+import org.eclipse.sirius.diagram.sequence.description.MessageMapping;
+import org.eclipse.sirius.diagram.sequence.description.ReturnMessageMapping;
+import org.eclipse.sirius.diagram.sequence.description.SequenceDiagramDescription;
+import org.eclipse.sirius.diagram.sequence.description.util.DescriptionSwitch;
+
+/**
+ * A switch that will return the Target Types associated to a given element
+ * (here all elements are sequence diagram-specific) and feature corresponding
+ * to an Interpreted Expression. For example, for a NodeMapping :
+ * <p>
+ * <li>if the feature is semantic candidate expression, we return the domain
+ * class of the first valid container (representation element mapping or
+ * representation description).</li>
+ * <li>if the feature is any other interpreted expression, we return the domain
+ * class associated to this mapping</li>
+ * </p>
+ *
+ * Can return {@link Options#newNone()} if the given expression does not require
+ * any target type (for example, a Popup menu contribution only uses variables
+ * in its expressions).
+ *
+ * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a>
+ *
+ */
+public class SequenceDiagramInterpretedExpressionSwitch extends DescriptionSwitch<Option<Collection<String>>> {
+
+ /**
+ * Constant used in switches on feature id to consider the case when the
+ * feature must not be considered.
+ */
+ private static final int DO_NOT_CONSIDER_FEATURE = -1;
+
+ /**
+ * The feature containing the Interpreted expression.
+ */
+ protected EStructuralFeature feature;
+
+ /**
+ * Indicates if the feature must be considered.
+ */
+ protected boolean considereFeature;
+
+ /**
+ * The global switch to delegate the doSwitch method to.
+ */
+ protected IInterpretedExpressionTargetSwitch globalSwitch;
+
+ /**
+ * Default constructor.
+ *
+ * @param feature
+ * representationDescription
+ * @param targetSwitch
+ * the global switch
+ */
+ public SequenceDiagramInterpretedExpressionSwitch(EStructuralFeature feature, IInterpretedExpressionTargetSwitch targetSwitch) {
+ super();
+ this.feature = feature;
+ this.globalSwitch = targetSwitch;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> doSwitch(EObject theEObject) {
+ Option<Collection<String>> doSwitch = super.doSwitch(theEObject);
+ if (doSwitch != null) {
+ return doSwitch;
+ }
+ Collection<String> defaultResult = Sets.newLinkedHashSet();
+ return Options.newSome(defaultResult);
+ }
+
+ /**
+ * Changes the behavior of this switch : if true, then the feature will be
+ * considered to calculate target types ; if false, then the feature will be
+ * ignored.
+ *
+ * @param considerFeature
+ * true if the feature should be considered, false otherwise
+ */
+ public void setConsiderFeature(boolean considerFeature) {
+ this.considereFeature = considerFeature;
+ }
+
+ private int getFeatureId(EClass eClass) {
+ int featureID = DO_NOT_CONSIDER_FEATURE;
+ if (considereFeature && feature != null) {
+ featureID = eClass.getFeatureID(feature);
+ }
+ return featureID;
+ }
+
+ /**
+ * Returns the {@link RepresentationDescription} that contains the given
+ * element.
+ *
+ * @param element
+ * the element to get the {@link RepresentationDescription} from
+ * @return the {@link RepresentationDescription} that contains the given
+ * element, null if none found
+ */
+ protected EObject getRepresentationDescription(EObject element) {
+ EObject container = element.eContainer();
+ while (!(container instanceof RepresentationDescription)) {
+ container = container.eContainer();
+ }
+ return container;
+ }
+
+ /**
+ * Returns the first relevant for the given EObject, i.e. the first
+ * container from which a domain class can be determined.
+ * <p>
+ * For example, for a given NodeMapping will return the first
+ * ContainerMapping or DiagramRepresentationDescription that contains this
+ * mapping.
+ * </p>
+ *
+ * @param element
+ * the element to get the container from
+ * @return the first relevant for the given EObject, i.e. the first
+ * container from which a domain class can be determined
+ */
+ protected EObject getFirstRelevantContainer(EObject element) {
+ EObject container = element.eContainer();
+ while ((!(container instanceof RepresentationDescription)) && (!(container instanceof RepresentationElementMapping))) {
+ container = container.eContainer();
+ }
+ return container;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseSequenceDiagramDescription(SequenceDiagramDescription object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(object.eClass())) {
+ case DescriptionPackage.SEQUENCE_DIAGRAM_DESCRIPTION__ENDS_ORDERING:
+ case DescriptionPackage.SEQUENCE_DIAGRAM_DESCRIPTION__INSTANCE_ROLES_ORDERING:
+ Collection<String> target = Sets.newLinkedHashSet();
+ target.add(object.getDomainClass());
+ result = Options.newSome(target);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseDelimitedEventMapping(DelimitedEventMapping object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(DescriptionPackage.eINSTANCE.getDelimitedEventMapping())) {
+ case DescriptionPackage.DELIMITED_EVENT_MAPPING__STARTING_END_FINDER_EXPRESSION:
+ case DescriptionPackage.DELIMITED_EVENT_MAPPING__FINISHING_END_FINDER_EXPRESSION:
+ Collection<String> target = Sets.newLinkedHashSet();
+ // LEt the global swith return the same types than precondition.
+ Option<Collection<String>> types = globalSwitch.doSwitch(object, false);
+ if (types.some()) {
+ target.addAll(types.get());
+ }
+ result = Options.newSome(target);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseFrameMapping(FrameMapping object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(DescriptionPackage.eINSTANCE.getFrameMapping())) {
+ case DescriptionPackage.FRAME_MAPPING__CENTER_LABEL_EXPRESSION:
+ case DescriptionPackage.FRAME_MAPPING__COVERED_LIFELINES_EXPRESSION:
+ case DO_NOT_CONSIDER_FEATURE:
+ Collection<String> target = Sets.newLinkedHashSet();
+ target.add(object.getDomainClass());
+ result = Options.newSome(target);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseMessageMapping(MessageMapping object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(DescriptionPackage.eINSTANCE.getMessageMapping())) {
+ case DescriptionPackage.MESSAGE_MAPPING__RECEIVING_END_FINDER_EXPRESSION:
+ case DescriptionPackage.MESSAGE_MAPPING__SENDING_END_FINDER_EXPRESSION:
+ Collection<String> target = Sets.newLinkedHashSet();
+ // LEt the global swith return the same types than precondition.
+ Option<Collection<String>> types = globalSwitch.doSwitch(object, false);
+ if (types.some()) {
+ target.addAll(types.get());
+ }
+ result = Options.newSome(target);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseReturnMessageMapping(ReturnMessageMapping object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(DescriptionPackage.eINSTANCE.getReturnMessageMapping())) {
+ case DescriptionPackage.RETURN_MESSAGE_MAPPING__INVOCATION_MESSAGE_FINDER_EXPRESSION:
+ Collection<String> target = Sets.newLinkedHashSet();
+ // LEt the global switch return the same types than precondition.
+ Option<Collection<String>> types = globalSwitch.doSwitch(object, false);
+ if (types.some()) {
+ target.addAll(types.get());
+ }
+ result = Options.newSome(target);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramTypeProvider.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramTypeProvider.java
new file mode 100644
index 0000000000..0fa8ba3175
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/api/diagramtype/SequenceDiagramTypeProvider.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.api.diagramtype;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.command.CommandParameter;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.business.api.diagramtype.HeaderData;
+import org.eclipse.sirius.business.api.diagramtype.ICollapseUpdater;
+import org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider;
+import org.eclipse.sirius.business.api.dialect.description.DefaultInterpretedExpressionTargetSwitch;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionTargetSwitch;
+import org.eclipse.sirius.business.api.query.DiagramElementMappingQuery;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.tool.AbstractVariable;
+import org.eclipse.sirius.description.tool.ToolPackage;
+import org.eclipse.sirius.diagram.business.api.query.DDiagramGraphicalQuery;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.InstanceRoleQuery;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionFactory;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.description.provider.DescriptionItemProviderAdapterFactory;
+import org.eclipse.sirius.diagram.sequence.description.tool.CombinedFragmentCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ExecutionCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InstanceRoleCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InstanceRoleReorderTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InteractionUseCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.MessageCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ObservationPointCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.OperandCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ReorderTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.SequenceDiagramToolDescription;
+import org.eclipse.sirius.diagram.sequence.description.tool.StateCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ToolFactory;
+import org.eclipse.sirius.diagram.sequence.description.tool.provider.ToolItemProviderAdapterFactory;
+import org.eclipse.sirius.diagram.sequence.ordering.provider.OrderingItemProviderAdapterFactory;
+import org.eclipse.sirius.diagram.sequence.provider.SequenceItemProviderAdapterFactory;
+import org.eclipse.sirius.diagram.sequence.template.provider.TemplateItemProviderAdapterFactory;
+import org.eclipse.sirius.diagram.sequence.ui.business.internal.diagramtype.SequenceCollapseUpdater;
+import org.eclipse.sirius.diagram.sequence.ui.business.internal.diagramtype.SequenceToolInterpretedExpressionSwitch;
+
+/**
+ * Provides diagram description for Sequence diagram.
+ *
+ * @author ymortier, pcdavid
+ */
+public class SequenceDiagramTypeProvider implements IDiagramDescriptionProvider {
+
+ private final Predicate<DSemanticDecorator> isSequenceSemanticDecorator = new Predicate<DSemanticDecorator>() {
+ public boolean apply(DSemanticDecorator input) {
+ boolean result = false;
+ if (input instanceof DDiagram) {
+ result = checkSequenceDescriptionPackage(((DDiagram) input).getDescription().eClass());
+ } else if (input instanceof DDiagramElement) {
+ result = isSequenceDDiagramElement.apply((DDiagramElement) input);
+ }
+ return result;
+ }
+ };
+
+ private final Predicate<DDiagramElement> isSequenceDDiagramElement = new Predicate<DDiagramElement>() {
+ public boolean apply(DDiagramElement input) {
+ // check that input has a Sequence mapping or is a simple node
+ // connected to a sequence message : a lost end.
+ DiagramElementMapping mappingToCheck = new DiagramElementMappingQuery(input.getDiagramElementMapping()).getRootMapping();
+ return checkSequenceDescriptionPackage(mappingToCheck.eClass()) || LostMessageEnd.viewpointElementPredicate().apply(input);
+ }
+ };
+
+ private boolean checkSequenceDescriptionPackage(EClass eClass) {
+ return DescriptionPackage.eINSTANCE.equals(eClass.getEPackage());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public DiagramDescription createDiagramDescription() {
+ return DescriptionFactory.eINSTANCE.createSequenceDiagramDescription();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<? extends CommandParameter> collectToolCommands(EObject context) {
+ Collection<CommandParameter> result = Lists.newArrayList();
+ Collection<EReference> refs = Arrays.asList(ToolPackage.Literals.TOOL_SECTION__OWNED_TOOLS, ToolPackage.Literals.TOOL_GROUP__TOOLS);
+ for (EReference ref : refs) {
+ if (ref.getEContainingClass().equals(context.eClass())) {
+ collectInstanceRoleCreation(result, ref);
+ collectExecutionCreation(result, ref);
+ collectStateCreation(result, ref);
+ collectMessageCreation(result, ref);
+ collectInteractionUse(result, ref);
+ collectCombinedFragmentCreation(result, ref);
+ collectOperandCreation(result, ref);
+ collectReorderCreations(result, ref);
+ collectObservationPointCreation(result, ref);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<? extends CommandParameter> collectMappingsCommands() {
+ Collection<CommandParameter> result = Lists.newArrayList();
+ // Nodes
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__NODE_MAPPINGS, DescriptionFactory.eINSTANCE.createInstanceRoleMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__NODE_MAPPINGS, DescriptionFactory.eINSTANCE.createExecutionMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__NODE_MAPPINGS, DescriptionFactory.eINSTANCE.createStateMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__NODE_MAPPINGS, DescriptionFactory.eINSTANCE.createEndOfLifeMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__NODE_MAPPINGS, DescriptionFactory.eINSTANCE.createObservationPointMapping()));
+ // Containers
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__CONTAINER_MAPPINGS, DescriptionFactory.eINSTANCE.createInteractionUseMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__CONTAINER_MAPPINGS, DescriptionFactory.eINSTANCE.createCombinedFragmentMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__CONTAINER_MAPPINGS, DescriptionFactory.eINSTANCE.createOperandMapping()));
+ // Edges
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__EDGE_MAPPINGS, DescriptionFactory.eINSTANCE.createBasicMessageMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__EDGE_MAPPINGS, DescriptionFactory.eINSTANCE.createReturnMessageMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__EDGE_MAPPINGS, DescriptionFactory.eINSTANCE.createCreationMessageMapping()));
+ result.add(new CommandParameter(null, org.eclipse.sirius.description.DescriptionPackage.Literals.LAYER__EDGE_MAPPINGS, DescriptionFactory.eINSTANCE.createDestructionMessageMapping()));
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public AdapterFactory getAdapterFactory() {
+ ComposedAdapterFactory composed = new ComposedAdapterFactory();
+ composed.addAdapterFactory(new SequenceItemProviderAdapterFactory());
+ composed.addAdapterFactory(new TemplateItemProviderAdapterFactory());
+ composed.addAdapterFactory(new DescriptionItemProviderAdapterFactory());
+ composed.addAdapterFactory(new OrderingItemProviderAdapterFactory());
+ composed.addAdapterFactory(new ToolItemProviderAdapterFactory());
+ return composed;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#handles(org.eclipse.emf.ecore.EPackage)
+ */
+ public boolean handles(EPackage ePackage) {
+ return DescriptionPackage.eINSTANCE.getNsURI().equals(ePackage.getNsURI())
+ || org.eclipse.sirius.diagram.sequence.description.tool.ToolPackage.eINSTANCE.getNsURI().equals(ePackage.getNsURI());
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#createInterpretedExpressionSwitch(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EStructuralFeature)
+ */
+ public IInterpretedExpressionTargetSwitch createInterpretedExpressionSwitch(EStructuralFeature feature, IInterpretedExpressionTargetSwitch parentSwitch) {
+ return new SequenceGlobalInterpretedTargetSwitch(feature, parentSwitch);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#allowsLayoutingModeActivation()
+ */
+ public boolean allowsLayoutingModeActivation() {
+ return false;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#allowsPinUnpin()
+ */
+ public Predicate<DDiagramElement> allowsPinUnpin() {
+ return Predicates.not(isSequenceDDiagramElement);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#allowsHideReveal()
+ */
+ public Predicate<DDiagramElement> allowsHideReveal() {
+ return Predicates.not(isSequenceDDiagramElement);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#allowsCopyPasteLayout()
+ */
+ public Predicate<DSemanticDecorator> allowsCopyPasteLayout() {
+ return Predicates.not(isSequenceSemanticDecorator);
+ }
+
+ private void collectInstanceRoleCreation(Collection<CommandParameter> result, EReference ref) {
+ InstanceRoleCreationTool instanceRoleCreationTool = ToolFactory.eINSTANCE.createInstanceRoleCreationTool();
+ addVariables(instanceRoleCreationTool);
+ result.add(new CommandParameter(null, ref, instanceRoleCreationTool));
+ }
+
+ private void collectExecutionCreation(Collection<CommandParameter> result, EReference ref) {
+ ExecutionCreationTool executionCreationTool = ToolFactory.eINSTANCE.createExecutionCreationTool();
+ addVariables(executionCreationTool);
+ result.add(new CommandParameter(null, ref, executionCreationTool));
+ }
+
+ private void collectStateCreation(Collection<CommandParameter> result, EReference ref) {
+ StateCreationTool stateCreationTool = ToolFactory.eINSTANCE.createStateCreationTool();
+ addVariables(stateCreationTool);
+ result.add(new CommandParameter(null, ref, stateCreationTool));
+ }
+
+ private void collectMessageCreation(Collection<CommandParameter> result, EReference ref) {
+ MessageCreationTool messageCreationTool = ToolFactory.eINSTANCE.createMessageCreationTool();
+ addVariables(messageCreationTool);
+ result.add(new CommandParameter(null, ref, messageCreationTool));
+ }
+
+ private void collectCombinedFragmentCreation(Collection<CommandParameter> result, EReference ref) {
+ CombinedFragmentCreationTool combinedFragmentCreationTool = ToolFactory.eINSTANCE.createCombinedFragmentCreationTool();
+ addVariables(combinedFragmentCreationTool);
+ result.add(new CommandParameter(null, ref, combinedFragmentCreationTool));
+ }
+
+ private void collectOperandCreation(Collection<CommandParameter> result, EReference ref) {
+ OperandCreationTool operandCreationTool = ToolFactory.eINSTANCE.createOperandCreationTool();
+ addVariables(operandCreationTool);
+ result.add(new CommandParameter(null, ref, operandCreationTool));
+ }
+
+ private void collectReorderCreations(Collection<CommandParameter> result, EReference ref) {
+ ReorderTool reorderCreationTool = ToolFactory.eINSTANCE.createReorderTool();
+ addVariables(reorderCreationTool);
+ result.add(new CommandParameter(null, ref, reorderCreationTool));
+
+ InstanceRoleReorderTool irReorderCreationTool = ToolFactory.eINSTANCE.createInstanceRoleReorderTool();
+ addVariables(irReorderCreationTool);
+ result.add(new CommandParameter(null, ref, irReorderCreationTool));
+ }
+
+ private void collectInteractionUse(Collection<CommandParameter> result, EReference ref) {
+ InteractionUseCreationTool interactionUseCreationTool = ToolFactory.eINSTANCE.createInteractionUseCreationTool();
+ addVariables(interactionUseCreationTool);
+ result.add(new CommandParameter(null, ref, interactionUseCreationTool));
+ }
+
+ private void collectObservationPointCreation(Collection<CommandParameter> result, EReference ref) {
+ ObservationPointCreationTool obsPointCreationTool = ToolFactory.eINSTANCE.createObservationPointCreationTool();
+ addVariables(obsPointCreationTool);
+ result.add(new CommandParameter(null, ref, obsPointCreationTool));
+ }
+
+ private void addVariables(SequenceDiagramToolDescription sequenceDiagramTool) {
+ for (EReference ref : sequenceDiagramTool.eClass().getEAllReferences()) {
+ if (ref.isContainment() && ref.getEType() instanceof EClass) {
+ EClass k = (EClass) ref.getEType();
+ EClass variable = org.eclipse.sirius.description.tool.ToolPackage.eINSTANCE.getAbstractVariable();
+ if (variable.isSuperTypeOf(k)) {
+ AbstractVariable var = (AbstractVariable) k.getEPackage().getEFactoryInstance().create(k);
+ EAnnotation annotation = ref.getEAnnotation("toolVariable");
+ if (annotation != null) {
+ var.setName(annotation.getDetails().get("name"));
+ } else {
+ var.setName(ref.getName());
+ }
+ sequenceDiagramTool.eSet(ref, var);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#supportHeader()
+ */
+ public boolean supportHeader() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider#getHeaderData()
+ */
+ public LinkedList<HeaderData> getHeaderData(DDiagram diagram) {
+ LinkedList<HeaderData> result = Lists.newLinkedList();
+ if (diagram instanceof SequenceDDiagram) {
+ Diagram gmfDiagram = getGmfDiagram(diagram);
+
+ if (gmfDiagram != null) {
+ Option<SequenceDiagram> optionalSequenceDiagram = ISequenceElementAccessor.getSequenceDiagram(gmfDiagram);
+ if (optionalSequenceDiagram.some()) {
+ Collection<InstanceRole> instanceRoles = optionalSequenceDiagram.get().getSortedInstanceRole();
+ for (InstanceRole instanceRole : instanceRoles) {
+ result.add(new InstanceRoleQuery(instanceRole).getHeaderData());
+ }
+ }
+
+ }
+ }
+ return result;
+ }
+
+ private Diagram getGmfDiagram(DDiagram diagram) {
+ Diagram gmfDiagram = null;
+ SequenceDDiagram sequenceDDiagram = (SequenceDDiagram) diagram;
+ Option<Diagram> optionDiagram = new DDiagramGraphicalQuery(sequenceDDiagram).getAssociatedGMFDiagram();
+ if (optionDiagram.some()) {
+ gmfDiagram = optionDiagram.get();
+ } else {
+ Resource eResource = diagram.eResource();
+ if (eResource != null) {
+ for (Diagram diag : Iterables.filter(eResource.getContents(), Diagram.class)) {
+ if (diagram.equals(diag.getElement())) {
+ gmfDiagram = diag;
+ break;
+ }
+ }
+ }
+ }
+ return gmfDiagram;
+ }
+
+ /**
+ * An {@link IInterpretedExpressionTargetSwitch} that delegates to the
+ * defaultSwitch or the diagram specific switch, according to the package of
+ * the considered element.
+ *
+ * @author <a href="mailto:maxime.porhel@obeo.fr">Maxime Porhel</a>
+ *
+ */
+ private class SequenceGlobalInterpretedTargetSwitch implements IInterpretedExpressionTargetSwitch {
+
+ private DefaultInterpretedExpressionTargetSwitch defaultSwitch;
+
+ private SequenceDiagramInterpretedExpressionSwitch sequenceSwitch;
+
+ private SequenceToolInterpretedExpressionSwitch toolSwitch;
+
+ public SequenceGlobalInterpretedTargetSwitch(EStructuralFeature feature, IInterpretedExpressionTargetSwitch parentSwitch) {
+ defaultSwitch = new DefaultInterpretedExpressionTargetSwitch(feature, parentSwitch);
+ sequenceSwitch = new SequenceDiagramInterpretedExpressionSwitch(feature, parentSwitch);
+ toolSwitch = new SequenceToolInterpretedExpressionSwitch(feature, parentSwitch);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionTargetSwitch#doSwitch(org.eclipse.emf.ecore.EObject)
+ */
+ public Option<Collection<String>> doSwitch(EObject target, boolean considerFeature) {
+ Collection<String> targetTypes = Sets.newLinkedHashSet();
+ Option<Collection<String>> expressionTarget = Options.newSome(targetTypes);
+ if (target != null) {
+ // Step 1 : apply the sequence diagram specific switch
+ sequenceSwitch.setConsiderFeature(considerFeature);
+ expressionTarget = sequenceSwitch.doSwitch(target);
+
+ // If no result has been found
+ if (expressionTarget.some() && expressionTarget.get().isEmpty()) {
+ // Step 2 : apply the sequence tool specific switch
+ toolSwitch.setConsiderFeature(considerFeature);
+ expressionTarget = toolSwitch.doSwitch(target);
+ }
+
+ // If no result has been found
+ if (expressionTarget.some() && expressionTarget.get().isEmpty()) {
+ // Step 3 : we use the default switch
+ expressionTarget = defaultSwitch.doSwitch(target, considerFeature);
+ }
+ }
+ return expressionTarget;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.diagramtype.IDiagramDescriptionProvider
+ * #getCollapseUpdater(org.eclipse.sirius.DDiagram)
+ */
+ public Option<? extends ICollapseUpdater> getCollapseUpdater(DDiagram diagram) {
+ if (diagram != null && diagram.getDescription() != null && handles(diagram.getDescription().eClass().getEPackage())) {
+ return Options.newSome(new SequenceCollapseUpdater());
+ }
+ return Options.newNone();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/EObjectQuery.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/EObjectQuery.java
new file mode 100644
index 0000000000..fbecdea807
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/EObjectQuery.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.internal;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.diagram.sequence.template.TSequenceDiagram;
+
+/**
+ * Class responsible for querying a model starting from an EObject.
+ *
+ * @author cbrun
+ *
+ */
+public class EObjectQuery {
+
+ private EObject start;
+
+ /**
+ * Create the query.
+ *
+ * @param start
+ * the EObject to start the query from.
+ */
+ public EObjectQuery(EObject start) {
+ this.start = start;
+ }
+
+ /**
+ * return the first TSequenceDiagram being parent of the current EObject.
+ *
+ * @return the first TSequenceDiagram being parent of the current EObject.
+ */
+ public Option<TSequenceDiagram> getParentSequenceDiagramTemplate() {
+ EObject cur = start;
+ while (cur != null) {
+ if (cur instanceof TSequenceDiagram) {
+ return Options.newSome((TSequenceDiagram) cur);
+ }
+ cur = cur.eContainer();
+ }
+ return Options.newNone();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/SequenceDiagramTemplateEdit.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/SequenceDiagramTemplateEdit.java
new file mode 100644
index 0000000000..6acd04dac8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/SequenceDiagramTemplateEdit.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.internal;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.emf.edit.command.CommandParameter;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.description.RepresentationTemplate;
+import org.eclipse.sirius.diagram.sequence.template.TSequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.template.TemplateFactory;
+import org.eclipse.sirius.diagram.sequence.template.TemplatePackage;
+import org.eclipse.sirius.diagram.sequence.template.TemplateToDiagramDescriptionTransformer;
+import org.eclipse.sirius.ui.business.api.template.RepresentationTemplateEdit;
+
+/**
+ * Implementation of a representation template Edit for the sequence diagram
+ * template.
+ *
+ * @author cbrun
+ *
+ */
+public class SequenceDiagramTemplateEdit implements RepresentationTemplateEdit {
+ /**
+ * {@inheritDoc}
+ */
+ public Object getNewChildDescriptor() {
+ return new CommandParameter(null, DescriptionPackage.Literals.VIEWPOINT__OWNED_TEMPLATES, TemplateFactory.eINSTANCE.createTSequenceDiagram());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public EObject getSourceElement(EObject vsmObject) {
+ Option<TSequenceDiagram> result = new EObjectQuery(vsmObject).getParentSequenceDiagramTemplate();
+ if (result.some()) {
+ TSequenceDiagram template = result.get();
+ ECrossReferenceAdapter crosser = getOrCreateCrossReferencer(template);
+ for (Setting setting : crosser.getInverseReferences(vsmObject)) {
+ if (setting.getEStructuralFeature() == TemplatePackage.eINSTANCE.getTTransformer_Outputs()) {
+ return setting.getEObject();
+ }
+
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void update(RepresentationTemplate template) {
+ if (template instanceof TSequenceDiagram) {
+ TemplateToDiagramDescriptionTransformer transformer = new TemplateToDiagramDescriptionTransformer((TSequenceDiagram) template);
+ transformer.refresh();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isGenerated(EObject vsmObject) {
+ return getSourceElement(vsmObject) != null;
+ }
+
+ private ECrossReferenceAdapter getOrCreateCrossReferencer(TSequenceDiagram template) {
+ ECrossReferenceAdapter crosser = ECrossReferenceAdapter.getCrossReferenceAdapter(template);
+ if (crosser == null) {
+ crosser = new ECrossReferenceAdapter();
+ template.eAdapters().add(crosser);
+ }
+ return crosser;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isOverriden(EObject eObj, EStructuralFeature feature) {
+ Option<TSequenceDiagram> result = new EObjectQuery(eObj).getParentSequenceDiagramTemplate();
+ if (result.some()) {
+ TSequenceDiagram template = result.get();
+ return new TemplateToDiagramDescriptionTransformer(template).isOverriding(eObj, feature);
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceCollapseUpdater.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceCollapseUpdater.java
new file mode 100644
index 0000000000..b979b7dc8d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceCollapseUpdater.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.internal.diagramtype;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.CollapseFilter;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.business.api.helper.graphicalfilters.CollapseUpdater;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ObservationPoint;
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.ICollapseMode;
+
+/**
+ * A specific @link
+ * {@link org.eclipse.sirius.business.api.diagramtype.ICollapseUpdater} to
+ * manage correctly the
+ * {@link org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution}
+ * .
+ *
+ * @author lredor
+ */
+public class SequenceCollapseUpdater extends CollapseUpdater {
+
+ private Predicate<DDiagramElement> specificCollapsePredicate = Predicates.or(AbstractNodeEvent.viewpointElementPredicate(), Lifeline.viewpointElementPredicate(),
+ ObservationPoint.viewpointElementPredicate());
+
+ /**
+ * Default constructor.
+ */
+ public SequenceCollapseUpdater() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void synchronizeCollapseFiltersAndGMFBounds(DDiagramElement element, Option<Node> optionalNode, boolean add, Class<? extends CollapseFilter> kindOfFilter) {
+
+ if (InstanceRole.viewpointElementPredicate().apply(element))
+ return;
+
+ super.synchronizeCollapseFiltersAndGMFBounds(element, optionalNode, add, kindOfFilter);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.helper.graphicalfilters.CollapseUpdater#collapseBounds(org.eclipse.gmf.runtime.notation.Node,
+ * org.eclipse.sirius.DDiagramElement)
+ */
+ public void collapseBounds(Node node, DDiagramElement element) {
+ if (!specificCollapsePredicate.apply(element)) {
+ super.collapseBounds(node, element);
+ } else {
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ Bounds bounds = (Bounds) layoutConstraint;
+ Bounds newBounds = NotationFactory.eINSTANCE.createBounds();
+ // Initialize the collapsed bounds
+ newBounds.setX(bounds.getX() + bounds.getWidth() / 2);
+ newBounds.setWidth(ICollapseMode.COLLAPSED_DIMENSION.width);
+
+ int newY = bounds.getY();
+ int newHeight = bounds.getHeight();
+ if (ObservationPoint.notationPredicate().apply(node)) {
+ newY = bounds.getY() + bounds.getHeight() / 2;
+ newHeight = ICollapseMode.COLLAPSED_DIMENSION.height;
+ }
+ newBounds.setY(newY);
+ newBounds.setHeight(newHeight);
+ node.setLayoutConstraint(newBounds);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.helper.graphicalfilters.CollapseUpdater#getExpandedBounds(org.eclipse.gmf.runtime.notation.Node,
+ * org.eclipse.sirius.DDiagramElement)
+ */
+ @Override
+ public Option<Bounds> getExpandedBounds(Node node, DDiagramElement element) {
+ Option<Bounds> optionalBounds;
+ if (!specificCollapsePredicate.apply(element)) {
+ optionalBounds = super.getExpandedBounds(node, element);
+ } else {
+ CollapseFilter filter = Iterables.getFirst(Iterables.filter(element.getGraphicalFilters(), CollapseFilter.class), null);
+ if (filter != null) {
+ optionalBounds = getExpandedBounds(node, new Dimension(filter.getWidth(), filter.getHeight()));
+ } else {
+ optionalBounds = Options.newNone();
+ }
+ }
+ return optionalBounds;
+ }
+
+ /**
+ * Get the expanded bounds of this node (the bound of this node must be in
+ * collapsed state before calling this method).
+ *
+ * @param node
+ * The node to expand.
+ * @param expandedSize
+ * The expanded size of this node
+ * @return An optional bounds. The bounds can be null. For example, if the
+ * current layout constraint of the <code>node</code> is not a
+ * Bounds.
+ */
+ public Option<Bounds> getExpandedBounds(Node node, Dimension expandedSize) {
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ Bounds bounds = (Bounds) layoutConstraint;
+ Bounds newBounds = NotationFactory.eINSTANCE.createBounds();
+ newBounds.setX(bounds.getX() - expandedSize.width / 2);
+ int newY = bounds.getY();
+ if (ObservationPoint.notationPredicate().apply(node)) {
+ newY = bounds.getY() - expandedSize.height / 2;
+ }
+ newBounds.setY(newY);
+ newBounds.setWidth(expandedSize.width);
+ newBounds.setHeight(expandedSize.height);
+ return Options.newSome(newBounds);
+ }
+ return Options.newNone();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceToolInterpretedExpressionSwitch.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceToolInterpretedExpressionSwitch.java
new file mode 100644
index 0000000000..969c2e4e0f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/diagramtype/SequenceToolInterpretedExpressionSwitch.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.internal.diagramtype;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.business.api.dialect.description.IInterpretedExpressionTargetSwitch;
+import org.eclipse.sirius.description.RepresentationDescription;
+import org.eclipse.sirius.description.RepresentationElementMapping;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+import org.eclipse.sirius.description.tool.ChangeContext;
+import org.eclipse.sirius.diagram.sequence.description.EventMapping;
+import org.eclipse.sirius.diagram.sequence.description.InstanceRoleMapping;
+import org.eclipse.sirius.diagram.sequence.description.tool.InstanceRoleReorderTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.MessageCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ReorderTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ToolPackage;
+import org.eclipse.sirius.diagram.sequence.description.tool.util.ToolSwitch;
+
+/**
+ * A switch that will return the Target Types associated to a given element
+ * (part of the {@link ToolPackage}) and feature corresponding to an Interpreted
+ * Expression. For example, for a NodeMapping :
+ * <p>
+ * <li>if the feature is semantic candidate expression, we return the domain
+ * class of the first valid container (representation element mapping or
+ * representation description).</li>
+ * <li>if the feature is any other interpreted expression, we return the domain
+ * class associated to this mapping</li>
+ * </p>
+ *
+ * Can return {@link Options#newNone()} if the given expression does not require
+ * any target type (for example, a Popup menu contribution only uses variables
+ * in its expressions).
+ *
+ * @author <a href="mailto:maxime.porhel@obeo.fr">Maxime Porhel</a>
+ */
+public class SequenceToolInterpretedExpressionSwitch extends ToolSwitch<Option<Collection<String>>> {
+
+ /**
+ * Constant used in switches on feature id to consider the case when the
+ * feature must not be considered.
+ */
+ private static final int DO_NOT_CONSIDER_FEATURE = -1;
+
+ /**
+ * The ID of the feature containing the Interpreted expression.
+ */
+ protected EStructuralFeature feature;
+
+ /**
+ * Indicates if the feature should be considered.
+ */
+ protected boolean considerFeature;
+
+ private IInterpretedExpressionTargetSwitch globalSwitch;
+
+ /**
+ * Default constructor.
+ *
+ * @param feature
+ * the feature containing the Interpreted expression
+ * @param defaultInterpretedExpressionTargetSwitch
+ * the global switch to use
+ */
+ public SequenceToolInterpretedExpressionSwitch(EStructuralFeature feature, IInterpretedExpressionTargetSwitch defaultInterpretedExpressionTargetSwitch) {
+ super();
+ this.feature = feature;
+ this.globalSwitch = defaultInterpretedExpressionTargetSwitch;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.tool.util.ToolSwitch#doSwitch(org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public Option<Collection<String>> doSwitch(EObject theEObject) {
+ Option<Collection<String>> doSwitch = super.doSwitch(theEObject);
+ if (doSwitch != null) {
+ return doSwitch;
+ }
+
+ Collection<String> targets = Collections.emptySet();
+ return Options.newSome(targets);
+ }
+
+ /**
+ * Changes the behavior of this switch : if true, then the feature will be
+ * considered to calculate target types ; if false, then the feature will be
+ * ignored.
+ *
+ * @param considerFeature
+ * true if the feature should be considered, false otherwise
+ */
+ public void setConsiderFeature(boolean considerFeature) {
+ this.considerFeature = considerFeature;
+ }
+
+ private int getFeatureId(EClass eClass) {
+ int featureID = DO_NOT_CONSIDER_FEATURE;
+ if (considerFeature && feature != null) {
+ featureID = eClass.getFeatureID(feature);
+ }
+ return featureID;
+ }
+
+ /**
+ * Returns the first element that changes the context of expressions. For
+ * example : for a given operation, will return the first ChangeContext or
+ * AbstractTool that contains it.
+ *
+ * @param element
+ * the element to get the container from
+ * @return the first relevant for the given EObject, i.e. the first
+ * container from which a domain class can be determined
+ */
+ protected EObject getFirstContextChangingContainer(EObject element) {
+ EObject container = element.eContainer();
+ while ((!(container instanceof RepresentationDescription)) && (!(container instanceof ChangeContext))
+ && (!(container instanceof AbstractToolDescription) && (!(container instanceof RepresentationElementMapping)))) {
+ container = container.eContainer();
+ }
+ return container;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseMessageCreationTool(MessageCreationTool object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(ToolPackage.eINSTANCE.getMessageCreationTool())) {
+ case ToolPackage.MESSAGE_CREATION_TOOL__CONNECTION_START_PRECONDITION:
+ case ToolPackage.MESSAGE_CREATION_TOOL__PRECONDITION:
+ case DO_NOT_CONSIDER_FEATURE:
+ Collection<String> targets = Sets.newLinkedHashSet();
+ for (RepresentationElementMapping correspondingMapping : Iterables.concat(object.getEdgeMappings(), object.getExtraSourceMappings())) {
+ Option<Collection<String>> targetsFromMapping = globalSwitch.doSwitch(correspondingMapping, false);
+ if (targetsFromMapping.some()) {
+ targets.addAll(targetsFromMapping.get());
+ }
+ }
+ result = Options.newSome(targets);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseReorderTool(ReorderTool object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(ToolPackage.eINSTANCE.getReorderTool())) {
+ case ToolPackage.REORDER_TOOL__PRECONDITION:
+ case DO_NOT_CONSIDER_FEATURE:
+ Collection<String> targets = Sets.newLinkedHashSet();
+ for (EventMapping correspondingMapping : object.getMappings()) {
+ Option<Collection<String>> targetsFromMapping = globalSwitch.doSwitch(correspondingMapping, false);
+ if (targetsFromMapping.some()) {
+ targets.addAll(targetsFromMapping.get());
+ }
+ }
+ result = Options.newSome(targets);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Collection<String>> caseInstanceRoleReorderTool(InstanceRoleReorderTool object) {
+ Option<Collection<String>> result = null;
+ switch (getFeatureId(ToolPackage.eINSTANCE.getInstanceRoleReorderTool())) {
+ case ToolPackage.INSTANCE_ROLE_REORDER_TOOL__PRECONDITION:
+ case DO_NOT_CONSIDER_FEATURE:
+ Collection<String> targets = Sets.newLinkedHashSet();
+ for (InstanceRoleMapping correspondingMapping : object.getMappings()) {
+ Option<Collection<String>> targetsFromMapping = globalSwitch.doSwitch(correspondingMapping, false);
+ if (targetsFromMapping.some()) {
+ targets.addAll(targetsFromMapping.get());
+ }
+ }
+ result = Options.newSome(targets);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/migration/SequenceDiagramRepresentationsFileMigrationParticipant.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/migration/SequenceDiagramRepresentationsFileMigrationParticipant.java
new file mode 100644
index 0000000000..682b711729
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/migration/SequenceDiagramRepresentationsFileMigrationParticipant.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.internal.migration;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.osgi.framework.Version;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.CollapseFilter;
+import org.eclipse.sirius.DAnalysis;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.DNodeList;
+import org.eclipse.sirius.DView;
+import org.eclipse.sirius.GraphicalFilter;
+import org.eclipse.sirius.IndirectlyCollapseFilter;
+import org.eclipse.sirius.SiriusFactory;
+import org.eclipse.sirius.business.api.migration.AbstractRepresentationsFileMigrationParticipant;
+import org.eclipse.sirius.diagram.business.api.query.DDiagramGraphicalQuery;
+import org.eclipse.sirius.diagram.business.api.query.NodeQuery;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNode2EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNode3EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNode4EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainer2EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeList2EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeListEditPart;
+import org.eclipse.sirius.diagram.part.SiriusVisualIDRegistry;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.ui.business.internal.diagramtype.SequenceCollapseUpdater;
+
+/**
+ * Migration contribution for sequence diagram part of representations file.
+ *
+ * @author mporhel
+ */
+public class SequenceDiagramRepresentationsFileMigrationParticipant extends AbstractRepresentationsFileMigrationParticipant {
+ /**
+ * The latest VP version for this participant.
+ */
+ private static final Version MIGRATION_VERSION = new Version("6.5.3.201301221200");
+
+ private Predicate<Node> isNode = new IsNode();
+
+ private Predicate<Node> isCollapsedNode = new IsCollapsedNode();
+
+ private Predicate<Node> isDirectlyCollapsedNode = new IsDirectlyCollapsedNode();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.migration.IMigrationParticipant#getMigrationVersion()
+ */
+ public Version getMigrationVersion() {
+ return MIGRATION_VERSION;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void postLoad(DAnalysis dAnalysis, Version loadedVersion) {
+ super.postLoad(dAnalysis, loadedVersion);
+
+ List<Diagram> sequenceDiagrams = getGMFSequenceDiagrams(dAnalysis);
+ if (!sequenceDiagrams.isEmpty()) {
+ migrateGMFBoundsOfCollapsedBorderedNode(sequenceDiagrams);
+ }
+ }
+
+ /**
+ * Retrieve all GMF diagrams of the {@link DAnalysis}.
+ *
+ * @param dAnalysis
+ * The analysis of the resource to migrate
+ * @return Sequence GMF diagrams of this {@link DAnalysis}
+ */
+ protected List<Diagram> getGMFSequenceDiagrams(DAnalysis dAnalysis) {
+ List<Diagram> diagrams = new ArrayList<Diagram>();
+
+ for (DView view : dAnalysis.getOwnedViews()) {
+ for (SequenceDDiagram diagram : Iterables.filter(view.getOwnedRepresentations(), SequenceDDiagram.class)) {
+ DDiagramGraphicalQuery query = new DDiagramGraphicalQuery((DDiagram) diagram);
+ Option<Diagram> option = query.getAssociatedGMFDiagram();
+ if (option.some()) {
+ diagrams.add(option.get());
+ }
+ }
+ }
+
+ return diagrams;
+ }
+
+ private void migrateGMFBoundsOfCollapsedBorderedNode(List<Diagram> sequenceDiagrams) {
+ for (Diagram diagram : sequenceDiagrams) {
+ // 1-Add new IndirectlyCollapseFilter
+ migrateChildrenOfCollapsedNode(diagram);
+ // 2-Set width and height of graphical filters of collapsed nodes
+ // (directly or not) with GMF size and set GMF bounds.
+ Iterator<Node> viewIterator = Iterators.filter(Iterators.filter(diagram.eAllContents(), Node.class), Predicates.and(isNode, isCollapsedNode));
+ while (viewIterator.hasNext()) {
+ Node node = viewIterator.next();
+ DNode dNode = (DNode) node.getElement();
+
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ Bounds bounds = (Bounds) layoutConstraint;
+ // The GMF node size must be stored in collapse filter (to
+ // can
+ // set this size when this node is expanded).
+ for (GraphicalFilter graphicalFilter : dNode.getGraphicalFilters()) {
+ if (graphicalFilter instanceof CollapseFilter) {
+ ((CollapseFilter) graphicalFilter).setWidth(bounds.getWidth());
+ ((CollapseFilter) graphicalFilter).setHeight(bounds.getHeight());
+ }
+ }
+ // Set new collapsed GMF bounds
+ SequenceCollapseUpdater scbu = new SequenceCollapseUpdater();
+ scbu.collapseBounds(node, dNode);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a {@link IndirectlyCollapsedFilter} to the children of CollapsedNode
+ * (to retrieve the same behavior as before). The migration of GMF bounds of
+ * this indirectly collapsed nodes, if they are bordered nodes, are deal
+ * later in method {{@link #migrateGMFBoundsOfBorderedNodes(List)}.
+ *
+ * @param diagram
+ * GMF Diagram to migrate.
+ */
+ private void migrateChildrenOfCollapsedNode(Diagram diagram) {
+ List<DDiagramElement> indirectlyCollaspedDDEs = Lists.newArrayList();
+ Iterator<Node> viewIterator = Iterators.filter(Iterators.filter(diagram.eAllContents(), Node.class), isDirectlyCollapsedNode);
+ while (viewIterator.hasNext()) {
+ final Node node = viewIterator.next();
+ if (node.getElement() instanceof AbstractDNode) {
+ AbstractDNode abstractDNode = (AbstractDNode) node.getElement();
+ indirectlyCollaspedDDEs.addAll(abstractDNode.getOwnedBorderedNodes());
+ if (abstractDNode instanceof DNodeContainer) {
+ DNodeContainer dDiagramElementContainer = (DNodeContainer) abstractDNode;
+ indirectlyCollaspedDDEs.addAll(dDiagramElementContainer.getOwnedDiagramElements());
+ } else if (abstractDNode instanceof DNodeList) {
+ DNodeList dNodeList = (DNodeList) abstractDNode;
+ indirectlyCollaspedDDEs.addAll(dNodeList.getOwnedElements());
+ }
+ }
+ }
+ for (DDiagramElement indirectlyCollaspedDDE : indirectlyCollaspedDDEs) {
+ IndirectlyCollapseFilter indirectlyCollapseFilter = SiriusFactory.eINSTANCE.createIndirectlyCollapseFilter();
+ indirectlyCollaspedDDE.getGraphicalFilters().add(indirectlyCollapseFilter);
+ }
+ }
+
+ /**
+ * Predicate that checks that :
+ * <UL>
+ * <LI>The input is a GMF Node,</LI>
+ * <LI>and this Node is a viewpoint node.</LI>
+ * </UL>
+ */
+ private static class IsNode implements Predicate<Node> {
+ public boolean apply(Node input) {
+ int type = SiriusVisualIDRegistry.getVisualID(input.getType());
+ return type == DNodeEditPart.VISUAL_ID || type == DNode2EditPart.VISUAL_ID || type == DNode3EditPart.VISUAL_ID || type == DNode4EditPart.VISUAL_ID;
+ }
+ }
+
+ /**
+ * Predicate that checks that this GMF Node is collapsed (directly or not).
+ *
+ * No check is done on the border position of a node because we need to
+ * handle ObservationPoints.
+ */
+ private static class IsCollapsedNode implements Predicate<Node> {
+ public boolean apply(Node input) {
+ return new NodeQuery(input).isCollapsed();
+ }
+ }
+
+ /**
+ * Predicate that checks that this GMF Node is directly collapsed.
+ *
+ * No check is done on the border position of a node because we need to
+ * handle ObservationPoints.
+ */
+ private static class IsDirectlyCollapsedNode implements Predicate<Node> {
+ public boolean apply(Node input) {
+ boolean apply = false;
+
+ int type = SiriusVisualIDRegistry.getVisualID(input.getType());
+ boolean result = type == DNode2EditPart.VISUAL_ID || type == DNode4EditPart.VISUAL_ID;
+ result = result || type == DNodeEditPart.VISUAL_ID || type == DNode3EditPart.VISUAL_ID;
+ result = result || type == DNodeContainerEditPart.VISUAL_ID || type == DNodeContainer2EditPart.VISUAL_ID;
+ result = result || type == DNodeListEditPart.VISUAL_ID || type == DNodeList2EditPart.VISUAL_ID;
+
+ if (result) {
+ return new NodeQuery(input).isDirectlyCollapsed();
+ }
+ return apply;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/refresh/VisibilityEventHandler.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/refresh/VisibilityEventHandler.java
new file mode 100644
index 0000000000..bb4cd1b89c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/business/internal/refresh/VisibilityEventHandler.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.business.internal.refresh;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListenerImpl;
+import org.eclipse.emf.transaction.RollbackException;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.ui.SequenceDiagramPlugin;
+import org.eclipse.sirius.diagram.sequence.ui.business.api.diagramtype.SequenceDiagramTypeProvider;
+import org.eclipse.sirius.diagram.sequence.util.NotificationQuery;
+
+/**
+ * A listener which refreshes and synchronizes the global ordering of elements
+ * after a command has been executed.
+ *
+ * @author pcdavid
+ */
+public class VisibilityEventHandler extends ResourceSetListenerImpl {
+ @Override
+ public boolean isPrecommitOnly() {
+ return true;
+ }
+
+ @Override
+ public boolean isPostcommitOnly() {
+ return false;
+ }
+
+ @Override
+ public boolean isAggregatePrecommitListener() {
+ return true;
+ }
+
+ /**
+ * Aborts any transaction which change the visibility of elements, as this
+ * is not supported in sequence diagrams.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
+ if (containsVisibilityEvent(event)) {
+ throw new RollbackException(new Status(IStatus.ERROR, SequenceDiagramPlugin.PLUGIN_ID, "Hide/Reveal is not supported in Sequence Diagrams"));
+ }
+ return null;
+ }
+
+ private boolean containsVisibilityEvent(ResourceSetChangeEvent event) {
+ Predicate<Notification> isVisibilityEvent = new Predicate<Notification>() {
+ public boolean apply(Notification input) {
+ NotificationQuery nq = new NotificationQuery(input);
+ return nq.isViewBecomingInvisibleEvent() || nq.isHideFilterAddEvent();
+ }
+ };
+
+ Predicate<Notification> isAlwaysVisibleSequenceElement = new Predicate<Notification>() {
+ public boolean apply(Notification input) {
+ Object notifier = input.getNotifier();
+ if (notifier instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) notifier;
+ DDiagram parentDiagram = dde.getParentDiagram();
+ return parentDiagram instanceof SequenceDDiagram && !(new SequenceDiagramTypeProvider().allowsHideReveal().apply(dde));
+ }
+ return false;
+ }
+ };
+ return Iterables.any(Iterables.filter(event.getNotifications(), Notification.class), Predicates.and(isAlwaysVisibleSequenceElement, isVisibilityEvent));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/api/SequenceDiagramLayout.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/api/SequenceDiagramLayout.java
new file mode 100644
index 0000000000..6ea13852bd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/api/SequenceDiagramLayout.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.api;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.SequenceLayout;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+
+/**
+ * API class to allow clients to control some aspects of the layout of sequence
+ * diagrams graphically.
+ *
+ * @author pcdavid
+ */
+public class SequenceDiagramLayout {
+ private final DiagramEditPart sequenceDiagram;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram to manage.
+ */
+ public SequenceDiagramLayout(DiagramEditPart sequenceDiagram) {
+ this.sequenceDiagram = Preconditions.checkNotNull(sequenceDiagram);
+ }
+
+ /**
+ * Updates the layout of the diagram so that the graphical coverage of
+ * Interaction Uses and Combined Fragments match the corresponding semantic
+ * coverage. This method should be called in the context of a transaction
+ * when the semantic model has changed in a way which may modify the
+ * semantic coverage of the elements on the diagram.
+ */
+ public void refreshGraphicalCoverage() {
+ if (sequenceDiagram instanceof SequenceDiagramEditPart) {
+ new SequenceLayout(sequenceDiagram.getDiagramView()).horizontalLayout(false);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceDelegatingCommandFactory.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceDelegatingCommandFactory.java
new file mode 100644
index 0000000000..0a338b2659
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceDelegatingCommandFactory.java
@@ -0,0 +1,384 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+import org.eclipse.sirius.description.tool.NodeCreationDescription;
+import org.eclipse.sirius.description.tool.PaneBasedSelectionWizardDescription;
+import org.eclipse.sirius.description.tool.SelectionWizardDescription;
+import org.eclipse.sirius.description.tool.ToolDescription;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshSemanticOrderingsOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.tool.ToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.description.tool.CombinedFragmentCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ExecutionCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InstanceRoleCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InteractionUseCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ObservationPointCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.OperandCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.StateCreationTool;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.DelegatingDiagramCommandFactory;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+
+/**
+ * A specialized diagram command factory which knows how to handle the
+ * additional variables passed to sequence tools.
+ *
+ *
+ * @author mporhel
+ */
+public final class SequenceDelegatingCommandFactory extends DelegatingDiagramCommandFactory {
+ /** The editing domain. */
+ private final TransactionalEditingDomain domain;
+
+ private final SequenceDiagram seqDiag;
+
+ private EObject predecessor;
+
+ private EventEnd startingEndPredecessor;
+
+ private EventEnd finishingEndPredecessor;
+
+ private EventEnd endBefore;
+
+ private List<EObject> coverage;
+
+ private Point location;
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the base command factory.
+ * @param domain
+ * the current editing domain.
+ * @param seqDiag
+ * the current sequence diagram.
+ */
+ private SequenceDelegatingCommandFactory(IDiagramCommandFactory baseFactory, TransactionalEditingDomain domain, SequenceDiagram seqDiag) {
+ super(baseFactory);
+ this.domain = domain;
+ this.seqDiag = seqDiag;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the base command factory.
+ * @param domain
+ * the current editing domain.
+ * @param seqDiag
+ * the current sequence diagram.
+ * @param startPredecessor
+ * the first click end predecessor.
+ * @param finishPredecessor
+ * the second click end predecessor.
+ */
+ public SequenceDelegatingCommandFactory(IDiagramCommandFactory baseFactory, TransactionalEditingDomain domain, SequenceDiagram seqDiag, EventEnd startPredecessor, EventEnd finishPredecessor) {
+ this(baseFactory, domain, seqDiag);
+ this.startingEndPredecessor = startPredecessor;
+ this.finishingEndPredecessor = finishPredecessor;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the base command factory.
+ * @param domain
+ * the current editing domain.
+ * @param seqDiag
+ * the current sequence diagram.
+ * @param startingEndPredecessor
+ * the first click end predecessor.
+ * @param finishingEndPredecessor
+ * the second click end predecessor.
+ * @param coverage
+ * the semantic coverage.
+ */
+ public SequenceDelegatingCommandFactory(IDiagramCommandFactory baseFactory, TransactionalEditingDomain domain, SequenceDiagram seqDiag, EventEnd startingEndPredecessor,
+ EventEnd finishingEndPredecessor, List<EObject> coverage) {
+ this(baseFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor);
+ this.coverage = coverage;
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the base command factory.
+ * @param domain
+ * the current editing domain.
+ * @param seqDiag
+ * the current sequence diagram.
+ * @param startingEndPredecessor
+ * the first click end predecessor.
+ * @param finishingEndPredecessor
+ * the second click end predecessor.
+ * @param location
+ * the clic location.
+ */
+ public SequenceDelegatingCommandFactory(IDiagramCommandFactory baseFactory, TransactionalEditingDomain domain, SequenceDiagram seqDiag, EventEnd startingEndPredecessor,
+ EventEnd finishingEndPredecessor, Point location) {
+ this(baseFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor);
+ this.location = location;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the base command factory.
+ * @param domain
+ * the current editing domain.
+ * @param seqDiag
+ * the current sequence diagram.
+ * @param endBefore
+ * the end before the click.
+ * @param location
+ * the clic location.
+ *
+ */
+ public SequenceDelegatingCommandFactory(IDiagramCommandFactory baseFactory, TransactionalEditingDomain domain, SequenceDiagram seqDiag, EventEnd endBefore, Point location) {
+ this(baseFactory, domain, seqDiag);
+ this.endBefore = endBefore;
+ this.location = location;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the base command factory.
+ * @param domain
+ * the current editing domain.
+ * @param seqDiag
+ * the current sequence diagram.
+ * @param predecessor
+ * the semantic EObject before the click before the click.
+ * @param location
+ * the clic location.
+ *
+ */
+ public SequenceDelegatingCommandFactory(IDiagramCommandFactory baseFactory, TransactionalEditingDomain domain, SequenceDiagram seqDiag, EObject predecessor, Point location) {
+ this(baseFactory, domain, seqDiag);
+ this.predecessor = predecessor;
+ this.location = location;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public org.eclipse.emf.common.command.Command buildCreateContainerCommandFromTool(DDiagram diagram, ContainerCreationDescription tool) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, startingEndPredecessor)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else if (tool instanceof InteractionUseCreationTool) {
+ result = buildInteractionUseCreationFromTool(diagram, (InteractionUseCreationTool) tool);
+ } else if (tool instanceof CombinedFragmentCreationTool) {
+ result = buildCombinedFragmentCreationFromTool(diagram, (CombinedFragmentCreationTool) tool);
+ } else {
+ result = super.buildCreateContainerCommandFromTool(diagram, tool);
+ }
+ return result;
+ }
+
+ private org.eclipse.emf.common.command.Command buildInteractionUseCreationFromTool(DDiagram diagram, InteractionUseCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateInteractionUseCommandFromTool(diagram, tool, startingEndPredecessor, finishingEndPredecessor, coverage);
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation((SequenceDDiagram) diagram)));
+ return emfCommand;
+ }
+
+ private org.eclipse.emf.common.command.Command buildCombinedFragmentCreationFromTool(DDiagram diagram, CombinedFragmentCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateCombinedFragmentCommandFromTool(diagram, tool, startingEndPredecessor, finishingEndPredecessor, coverage);
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation((SequenceDDiagram) diagram)));
+ return emfCommand;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command buildGenericToolCommandFromTool(EObject containerView, ToolDescription tool) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, endBefore)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else {
+ result = buildSequenceGenericToolCommandFromTool(containerView, tool);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command buildSelectionWizardCommandFromTool(SelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, endBefore)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else {
+ result = buildSequenceSelectionWizardCommandFromTool(tool, dContainer, selectedElement);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command buildPaneBasedSelectionWizardCommandFromTool(PaneBasedSelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, endBefore)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else {
+ result = buildSequencePaneBasedSelectionWizardCommandFromTool(tool, dContainer, selectedElement);
+ }
+ return result;
+ }
+
+ private Command buildSequenceGenericToolCommandFromTool(EObject containerView, ToolDescription tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildSequenceGenericToolCommandFromTool(containerView, tool, endBefore, location, seqDiag.getNotationDiagram());
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(seqDiag.getSequenceDDiagram())));
+ return emfCommand;
+ }
+
+ private Command buildSequenceSelectionWizardCommandFromTool(SelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildSequenceSelectionWizardCommandFromTool(tool, dContainer, selectedElement, endBefore, location);
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(seqDiag.getSequenceDDiagram())));
+ return emfCommand;
+ }
+
+ private Command buildSequencePaneBasedSelectionWizardCommandFromTool(PaneBasedSelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildSequencePaneBasedSelectionWizardCommandFromTool(tool, dContainer, selectedElement, endBefore, location);
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(seqDiag.getSequenceDDiagram())));
+ return emfCommand;
+ }
+
+ @Override
+ public Command buildCreateNodeCommandFromTool(DDiagramElementContainer container, NodeCreationDescription tool) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, startingEndPredecessor)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else if (tool instanceof ObservationPointCreationTool) {
+ result = buildObservationPointCreationCommandFromTool(container, (ObservationPointCreationTool) tool);
+ } else {
+ result = super.buildCreateNodeCommandFromTool(container, tool);
+ }
+ return result;
+ }
+
+ @Override
+ public org.eclipse.emf.common.command.Command buildCreateNodeCommandFromTool(DNode node, NodeCreationDescription tool) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, startingEndPredecessor)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else if (tool instanceof InstanceRoleCreationTool) {
+ result = buildInstanceRoleCreationCommandFromTool(seqDiag.getSequenceDDiagram(), (InstanceRoleCreationTool) tool);
+ } else if (tool instanceof ExecutionCreationTool) {
+ result = buildExecutionCreationCommandFromTool(node, (ExecutionCreationTool) tool);
+ } else if (tool instanceof StateCreationTool) {
+ result = buildStateCreationCommandFromTool(node, (StateCreationTool) tool);
+ } else if (tool instanceof ObservationPointCreationTool) {
+ result = buildObservationPointCreationCommandFromTool(node, (ObservationPointCreationTool) tool);
+ } else {
+ result = super.buildCreateNodeCommandFromTool(node, tool);
+ }
+ return result;
+ }
+
+ @Override
+ public org.eclipse.emf.common.command.Command buildCreateNodeCommandFromTool(DDiagram diagram, NodeCreationDescription tool) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, startingEndPredecessor) || diagram != seqDiag.getSequenceDDiagram()) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else if (tool instanceof InstanceRoleCreationTool) {
+ result = buildInstanceRoleCreationCommandFromTool(seqDiag.getSequenceDDiagram(), (InstanceRoleCreationTool) tool);
+ } else if (tool instanceof ObservationPointCreationTool) {
+ result = buildObservationPointCreationCommandFromTool(seqDiag.getSequenceDDiagram(), (ObservationPointCreationTool) tool);
+ } else {
+ result = super.buildCreateNodeCommandFromTool(diagram, tool);
+ }
+ return result;
+ }
+
+ @Override
+ public org.eclipse.emf.common.command.Command buildCreateContainerCommandFromTool(DDiagramElementContainer nodeContainer, ContainerCreationDescription tool) {
+ final org.eclipse.emf.common.command.Command result;
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(seqDiag, startingEndPredecessor)) {
+ result = org.eclipse.emf.common.command.UnexecutableCommand.INSTANCE;
+ } else if (tool instanceof OperandCreationTool) {
+ result = buildOperandCreationCommandFromTool(nodeContainer, (OperandCreationTool) tool);
+ } else {
+ result = super.buildCreateContainerCommandFromTool(nodeContainer, tool);
+ }
+ return result;
+ }
+
+ private Command buildInstanceRoleCreationCommandFromTool(SequenceDDiagram diagram, InstanceRoleCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateInstanceRoleCommandFromTool(diagram, tool, predecessor, location);
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diagram)));
+ return emfCommand;
+ }
+
+ private org.eclipse.emf.common.command.Command buildExecutionCreationCommandFromTool(DNode node, ExecutionCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateExecutionCommandFromTool(node, tool, startingEndPredecessor, finishingEndPredecessor, location);
+ SequenceDDiagram diagram = (SequenceDDiagram) node.getParentDiagram();
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diagram)));
+ return emfCommand;
+ }
+
+ private org.eclipse.emf.common.command.Command buildObservationPointCreationCommandFromTool(DDiagramElement diagramElement, ObservationPointCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateObservationPointCommandFromTool(diagramElement, tool, startingEndPredecessor, finishingEndPredecessor);
+ SequenceDDiagram diagram = (SequenceDDiagram) diagramElement.getParentDiagram();
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diagram)));
+ return emfCommand;
+ }
+
+ private org.eclipse.emf.common.command.Command buildObservationPointCreationCommandFromTool(SequenceDDiagram diag, ObservationPointCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateObservationPointCommandFromTool(diag, tool, startingEndPredecessor, finishingEndPredecessor);
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diag)));
+ return emfCommand;
+ }
+
+ private org.eclipse.emf.common.command.Command buildStateCreationCommandFromTool(DNode node, StateCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateStateCommandFromTool(node, tool, startingEndPredecessor, finishingEndPredecessor);
+ SequenceDDiagram diagram = (SequenceDDiagram) node.getParentDiagram();
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diagram)));
+ return emfCommand;
+ }
+
+ private org.eclipse.emf.common.command.Command buildOperandCreationCommandFromTool(DDiagramElementContainer nodeContainer, OperandCreationTool tool) {
+ org.eclipse.emf.common.command.Command emfCommand = ToolCommandBuilder.buildCreateOperantCommandFromTool(nodeContainer, tool, startingEndPredecessor, finishingEndPredecessor);
+ SequenceDDiagram diagram = (SequenceDDiagram) nodeContainer.getParentDiagram();
+ emfCommand = emfCommand.chain(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diagram)));
+ return emfCommand;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceEMFCommandFactory.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceEMFCommandFactory.java
new file mode 100644
index 0000000000..130df4ae96
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/command/SequenceEMFCommandFactory.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.command.IdentityCommand;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.FixGraphicalOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshGraphicalOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshSemanticOrderingsOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetVerticalRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SynchronizeISequenceEventsSemanticOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ExecutionOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.OperandEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.tools.internal.command.UndoRedoCapableEMFCommandFactory;
+
+/**
+ * A custom EMF Command Factory to specialize the delete behavior for sequence
+ * diagram elements.
+ *
+ * @author pcdavid
+ */
+public final class SequenceEMFCommandFactory extends UndoRedoCapableEMFCommandFactory {
+
+ private final SequenceDiagramEditPart sdep;
+
+ /**
+ * Constructor.
+ *
+ * The factory will be initialized with the TransactionalEditingDomain of
+ * the current SequenceDiagramEditPart.
+ *
+ * @param sdep
+ * the sequence diagram.
+ */
+ public SequenceEMFCommandFactory(SequenceDiagramEditPart sdep) {
+ super(sdep.getEditingDomain());
+ this.sdep = sdep;
+ }
+
+ /**
+ * Overridden to reconnect the children of an execution about to be deleted.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public Command buildDeleteDiagramElement(DDiagramElement element) {
+ Command result = super.buildDeleteDiagramElement(element);
+ if (AbstractNodeEvent.viewpointElementPredicate().apply(element)) {
+ Object part = sdep.getViewer().getEditPartRegistry().get(element);
+ if (part instanceof ExecutionEditPart) {
+ ExecutionEditPart executionPart = (ExecutionEditPart) part;
+ result = getDeleteExecutionCommand(executionPart, result);
+ }
+ } else if (Operand.viewpointElementPredicate().apply(element)) {
+ Object part = sdep.getViewer().getEditPartRegistry().get(element);
+ if (part instanceof OperandEditPart) {
+ OperandEditPart operandPart = (OperandEditPart) part;
+ result = getDeleteOperandCommand(operandPart, result);
+ }
+ }
+ return result;
+ }
+
+ private Command getDeleteExecutionCommand(ExecutionEditPart executionPart, Command basicDelete) {
+ TransactionalEditingDomain ted = sdep.getEditingDomain();
+
+ CompoundCommand cc = new CompoundCommand();
+ cc.append(ExecutionOperations.getReconnectSubExecutionsToParentCommand(executionPart));
+ cc.append(ExecutionOperations.getReconnectEdgesToParentCommand(executionPart));
+ cc.append(basicDelete);
+ cc.append(CommandFactory.createRecordingCommand(ted, new RefreshSemanticOrderingsOperation((SequenceDDiagram) sdep.resolveSemanticElement())));
+ cc.append(CommandFactory.createRecordingCommand(ted, new FixGraphicalOrderingOperation((SequenceDDiagram) sdep.resolveSemanticElement())));
+ return cc;
+ }
+
+ private Command getDeleteOperandCommand(OperandEditPart operandPart, Command basicDelete) {
+ if (operandPart.getViewer().getSelectedEditParts().contains(operandPart.getParentCombinedFragmentEditPart())) {
+ // The operand container is also beeing deleted. Therefore we do not
+ // need to add delete operation on operand.
+ return IdentityCommand.INSTANCE;
+ } else {
+ return buildDeleteOperandCommand(operandPart, basicDelete);
+ }
+ }
+
+ private Command buildDeleteOperandCommand(OperandEditPart operandPart, Command basicDelete) {
+ TransactionalEditingDomain ted = sdep.getEditingDomain();
+ CompoundCommand cc = new CompoundCommand();
+ cc.append(basicDelete);
+
+ Operand deletedOperand = (Operand) operandPart.getISequenceEvent();
+ if (deletedOperand.getCombinedFragment().getOperands().size() == 1 || operandPart.getViewer().getSelectedEditParts().size() != 1) {
+ /*
+ * The last remaining operand can not be deleted. It is also not
+ * possible to delete 2 operand to avoid NPE in
+ * SetVerticalRangeOperation.
+ */
+ return UnexecutableCommand.INSTANCE;
+ }
+ Option<Operand> absorbingOperand = getAbsorbingOperand(deletedOperand);
+ assert absorbingOperand.some();
+ if (absorbingOperand.some()) {
+ Range expandedRange = absorbingOperand.get().getVerticalRange().union(deletedOperand.getVerticalRange());
+ cc.append(CommandFactory.createRecordingCommand(ted, new SetVerticalRangeOperation(absorbingOperand.get(), expandedRange)));
+ cc.append(CommandFactory.createRecordingCommand(ted, new RefreshSemanticOrderingsOperation((SequenceDDiagram) sdep.resolveSemanticElement())));
+ cc.append(CommandFactory.createRecordingCommand(ted, new RefreshGraphicalOrderingOperation(sdep.getSequenceDiagram())));
+ cc.append(CommandFactory.createRecordingCommand(ted, new SynchronizeISequenceEventsSemanticOrderingOperation(absorbingOperand.get())));
+ }
+
+ return cc;
+ }
+
+ /**
+ * Returns the sibling operand which should absorb the space previously
+ * occupied by the operand about to be deleted.
+ */
+ private Option<Operand> getAbsorbingOperand(Operand deletedOperand) {
+ assert deletedOperand != null;
+ if (deletedOperand.isFirstOperand()) {
+ return deletedOperand.getFollowingOperand();
+ } else {
+ return deletedOperand.getPreviousOperand();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ConnectionAnchorOperation.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ConnectionAnchorOperation.java
new file mode 100644
index 0000000000..78148e8800
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ConnectionAnchorOperation.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.requests.CreateConnectionRequest;
+import org.eclipse.gef.requests.DropRequest;
+import org.eclipse.gef.requests.ReconnectRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.internal.editparts.NoteAttachmentEditPart;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
+import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.diagram.internal.view.factories.ViewLocationHint;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.SequenceSlidableAnchor;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+
+/**
+ * Helper class to business code between different kinds of edit parts when
+ * inheritance is not possible or inconvenient.
+ *
+ * @author mporhel
+ */
+public final class ConnectionAnchorOperation {
+ private ConnectionAnchorOperation() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * If possible, returns an equivalent anchor to the one given, but
+ * horizontally centered on its owner.
+ *
+ * @param anchor
+ * the anchor.
+ * @return an equivalent anchor horizontally centered on its owner.
+ */
+ public static ConnectionAnchor getHorizontallyCenteredAnchor(ConnectionAnchor anchor) {
+ return getCorrectedAnchor(anchor, null, 0.5);
+ }
+
+ /**
+ * If possible, returns an equivalent anchor to the one given, but
+ * horizontally centered on its owner north face.
+ *
+ * @param anchor
+ * the anchor.
+ * @return an equivalent anchor horizontally centered on its owner north
+ * face.
+ */
+ public static ConnectionAnchor getHorizontallyCenteredAndTopAnchor(ConnectionAnchor anchor) {
+ return getCorrectedAnchor(anchor, "(0.5,0)", 0.5);
+ }
+
+ /**
+ * If possible, returns an equivalent anchor to the one given, but
+ * horizontally centered on its owner south face.
+ *
+ * @param anchor
+ * the anchor.
+ * @return an equivalent anchor horizontally centered on its owner north
+ * face.
+ */
+ public static ConnectionAnchor getHorizontallyCenteredAndBottomAnchor(ConnectionAnchor anchor) {
+ return getCorrectedAnchor(anchor, "(0.5,1)", 0.5);
+ }
+
+ private static ConnectionAnchor getCorrectedAnchor(ConnectionAnchor anchor, String defaultId, double preciseX) {
+ ConnectionAnchor result = anchor;
+ if (anchor instanceof SlidableAnchor) {
+ String id = ((SlidableAnchor) anchor).getTerminal();
+ if (StringUtil.isEmpty(id) && !StringUtil.isEmpty(defaultId)) {
+ id = defaultId;
+ }
+ if (!StringUtil.isEmpty(id)) {
+ PrecisionPoint pp = BaseSlidableAnchor.parseTerminalString(id);
+ if (pp != null) {
+ pp.preciseX = preciseX;
+ result = new SequenceSlidableAnchor(anchor, pp);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Adjusts the Y location of a request to match the Y location of the source
+ * anchor as stored by ViewLocationHint. This can be used before a call to
+ * {@link #getTargetConnectionAnchor(org.eclipse.gef.ConnectionEditPart)} to
+ * make sure a connection is horizontal.
+ *
+ * @param request
+ * the request to modify.
+ */
+ public static void matchRequestYLocationWithSourceAnchor(DropRequest request) {
+ if (request instanceof Request && !new RequestQuery((Request) request).isSequenceMessageCreation()) {
+ return;
+ } else if (request.getLocation() != null) {
+ Object sourceLocation = ViewLocationHint.getInstance().getData(ViewLocationHint.SOURCE_ANCHOR_LOCATION);
+ if (sourceLocation instanceof Point && request instanceof CreateConnectionRequest) {
+ EditPart sourceEP = ((CreateConnectionRequest) request).getSourceEditPart();
+ EditPart targetEP = ((CreateConnectionRequest) request).getTargetEditPart();
+ Point sourceLocationPoint = ((Point) sourceLocation).getCopy();
+ if (!sourceEP.equals(targetEP)) {
+ request.getLocation().y = sourceLocationPoint.y;
+ } else if (request.getLocation().y <= sourceLocationPoint.y) {
+ request.getLocation().y = sourceLocationPoint.y;
+ }
+ }
+ }
+ }
+
+ /**
+ * Return an horizontally centered anchor.
+ *
+ * @param self
+ * .
+ * @param request
+ * .
+ * @param superSourceAnchor
+ * .
+ * @return .
+ */
+ public static ConnectionAnchor getSourceConnectionAnchor(ISequenceEventEditPart self, Request request, ConnectionAnchor superSourceAnchor) {
+ ConnectionAnchor result = ConnectionAnchorOperation.getHorizontallyCenteredAnchor(superSourceAnchor);
+
+ if (request instanceof CreateConnectionRequest) {
+ CreateConnectionRequest ccr = (CreateConnectionRequest) request;
+ if (ccr.getLocation() == null) {
+ result = ConnectionAnchorOperation.getHorizontallyCenteredAndBottomAnchor(superSourceAnchor);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * During message creation, use the same y location as the corresponding
+ * source connection anchor, stored in ViewLocationHint, to improve user
+ * feedback.
+ *
+ * @param self
+ * .
+ * @param request
+ * .
+ * @param superTargetAnchor
+ * .
+ * @return .
+ */
+ public static ConnectionAnchor getTargetConnectionAnchor(ISequenceEventEditPart self, Request request, ConnectionAnchor superTargetAnchor) {
+ ConnectionAnchor result = ConnectionAnchorOperation.getHorizontallyCenteredAnchor(superTargetAnchor);
+ if (request instanceof CreateConnectionRequest) {
+ CreateConnectionRequest ccr = (CreateConnectionRequest) request;
+ if (ConnectionAnchorOperation.isCreateMessageToSelfRequest(ccr)) {
+ result = ConnectionAnchorOperation.getHorizontallyCenteredAndTopAnchor(superTargetAnchor);
+ } else {
+ result = ConnectionAnchorOperation.getHorizontallyCenteredAnchor(superTargetAnchor);
+ }
+ } else if (request instanceof ReconnectRequest && !(((ReconnectRequest) request).getConnectionEditPart() instanceof NoteAttachmentEditPart)) {
+ ReconnectRequest conn = (ReconnectRequest) request;
+ ConnectionEditPart cep = (ConnectionEditPart) conn.getConnectionEditPart();
+ result = cep.getConnectionFigure().getTargetAnchor();
+ } else {
+ result = superTargetAnchor;
+ }
+ return result;
+ }
+
+ private static boolean isCreateMessageToSelfRequest(CreateConnectionRequest ccr) {
+ if ((ccr.getSourceEditPart() instanceof ExecutionEditPart || ccr.getSourceEditPart() instanceof LifelineEditPart)
+ && (ccr.getTargetEditPart() instanceof ExecutionEditPart || ccr.getTargetEditPart() instanceof LifelineEditPart)) {
+ LifelineEditPart sourceParentLifeline = EditPartsHelper.findParentLifeline((IGraphicalEditPart) ccr.getSourceEditPart());
+ LifelineEditPart targetParentLifeline = EditPartsHelper.findParentLifeline((IGraphicalEditPart) ccr.getTargetEditPart());
+ return sourceParentLifeline.equals(targetParentLifeline);
+ }
+ return false;
+ }
+
+ /**
+ * Get an horizontally and vertically centered anchor.
+ *
+ * @param anchor
+ * an anchor.
+ * @return a centered anchor.
+ */
+ public static ConnectionAnchor safeCenterAnchor(ConnectionAnchor anchor) {
+ ConnectionAnchor result = anchor;
+ if (result != null) {
+ result = new SequenceSlidableAnchor(anchor, new PrecisionPoint(0.5, 0.5));
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/EndOfLifeOperations.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/EndOfLifeOperations.java
new file mode 100644
index 0000000000..d6a479bb0f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/EndOfLifeOperations.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.requests.BendpointRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.EndOfLifeEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * Helper class to factor common code for EndOfLife management.
+ *
+ * @author mporhel
+ */
+public final class EndOfLifeOperations {
+ private EndOfLifeOperations() {
+ // Prevent instantiations.
+ }
+
+ /**
+ * Shows or updates the lifeline source feedback for the given request.
+ *
+ * @param request
+ * request describing the type of feedback.
+ * @param endOfLifeEditPart
+ * current {@link EndOfLifeEditPart}.
+ * @param moveSource
+ * editpart source fo the current move.
+ */
+ public static void showEndOfLifeFeedback(Request request, EndOfLifeEditPart endOfLifeEditPart, IGraphicalEditPart moveSource) {
+ LifelineEditPart lifelineEditPart = (LifelineEditPart) endOfLifeEditPart.getParent();
+ Point location = EndOfLifeOperations.getLocation(request);
+
+ if (location == null) {
+ return;
+ }
+
+ lifelineEditPart.showSourceFeedback(EndOfLifeOperations.getLifelineResizeRequest(endOfLifeEditPart, lifelineEditPart, location, moveSource));
+ }
+
+ /**
+ * Erases for the specified {@link Request}.
+ * {@link #showSourceFeedback(Request)}.
+ *
+ * @param request
+ * the type of feedback that is being erased
+ * @param lep
+ * the current {@link LifelineEditPart}.
+ */
+ public static void eraseEndOfLifeFeedback(LifelineEditPart lep, Request request) {
+ Point location = null;
+ location = EndOfLifeOperations.getLocation(request);
+
+ if (location == null) {
+ return;
+ }
+
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ cbr.getMoveDelta().y = location.y - (lep.getFigure().getBounds().y + lep.getFigure().getBounds().height);
+ cbr.setEditParts(lep);
+ cbr.setLocation(location.getCopy());
+ lep.eraseSourceFeedback(cbr);
+ }
+
+ /**
+ * Compute a request to resize the lifeline, from a request on its end of
+ * life.
+ *
+ * @param request
+ * the type of feedback that is wanted.
+ * @param endOfLifeEditPart
+ * the current {@link EndOfLifeEditPart}.
+ * @param moveSource
+ * editpart source fo the current move.
+ * @return the computed request.
+ */
+ public static ChangeBoundsRequest getLifelineResizeRequest(Request request, EndOfLifeEditPart endOfLifeEditPart, IGraphicalEditPart moveSource) {
+ Point location = EndOfLifeOperations.getLocation(request);
+ if (endOfLifeEditPart.getParent() instanceof LifelineEditPart && location != null) {
+ LifelineEditPart lifelineEditPart = (LifelineEditPart) endOfLifeEditPart.getParent();
+ return EndOfLifeOperations.getLifelineResizeRequest(endOfLifeEditPart, lifelineEditPart, location, moveSource);
+ }
+ return null;
+ }
+
+ private static ChangeBoundsRequest getLifelineResizeRequest(EndOfLifeEditPart endOfLifeEditPart, LifelineEditPart lifelineEditPart, Point location, IGraphicalEditPart moveSource) {
+ GraphicalHelper.screen2logical(location, lifelineEditPart);
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ cbr.setResizeDirection(PositionConstants.SOUTH);
+ cbr.getSizeDelta().height = EndOfLifeOperations.computeResizeDelta(endOfLifeEditPart, lifelineEditPart, location.y, moveSource);
+ cbr.setEditParts(lifelineEditPart);
+ cbr.setLocation(location.getCopy());
+ return cbr;
+ }
+
+ private static int computeResizeDelta(EndOfLifeEditPart endOfLifeEditPart, LifelineEditPart lifelineEditPart, int location, IGraphicalEditPart moveSource) {
+ double zoom = GraphicalHelper.getZoom(lifelineEditPart);
+ int lifelineLocation = lifelineEditPart.getFigure().getBounds().y + lifelineEditPart.getFigure().getBounds().height;
+ int eolMidSize = endOfLifeEditPart.getFigure().getBounds().height / 2;
+ int feedbackRangeLimit = EndOfLifeOperations.getFeedBackRangeLimit(location, moveSource, eolMidSize, EndOfLifeOperations.getLastEventPosition(lifelineEditPart));
+ return (int) (EndOfLifeOperations.getResizeDelta(lifelineLocation, eolMidSize, feedbackRangeLimit) * zoom);
+ }
+
+ private static int getFeedBackRangeLimit(int location, IGraphicalEditPart moveSource, int eolMidSize, int lastEventInTargetInstanceRole) {
+ Rectangle sourceBbounds = moveSource.getFigure().getBounds();
+ int feedbackRangeLimit = location;
+ if (moveSource instanceof SequenceMessageEditPart) {
+ if (feedbackRangeLimit < sourceBbounds.y) {
+ feedbackRangeLimit = sourceBbounds.y;
+ } else if (lastEventInTargetInstanceRole + eolMidSize > location) {
+ feedbackRangeLimit = lastEventInTargetInstanceRole + eolMidSize;
+ } else if (location > sourceBbounds.y + sourceBbounds.height) {
+ feedbackRangeLimit = sourceBbounds.y + sourceBbounds.height;
+ }
+ }
+ return feedbackRangeLimit;
+ }
+
+ // limit the vertical move to the first sequence event of the targeted
+ // instance role
+ private static int getLastEventPosition(LifelineEditPart lifelineEditPart) {
+ int lastMessageInTargetInstanceRole = Integer.MIN_VALUE;
+ Range occupiedRange = lifelineEditPart.getISequenceEvent().getOccupiedRange();
+ if (!occupiedRange.isEmpty()) {
+ // limite the move to the first sequence event of the target
+ // lifeline
+ lastMessageInTargetInstanceRole = occupiedRange.getUpperBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ }
+ return lastMessageInTargetInstanceRole;
+ }
+
+ private static int getResizeDelta(int lifelineLocation, int eolMidSize, int feedbackRangeLimit) {
+ int delta = feedbackRangeLimit;
+ delta -= lifelineLocation;
+ delta -= eolMidSize;
+ return delta;
+ }
+
+ private static Point getLocation(Request request) {
+ Point location = null;
+ if (request instanceof BendpointRequest) {
+ BendpointRequest bendpointRequest = (BendpointRequest) request;
+ if (bendpointRequest.getLocation() != null) {
+ location = bendpointRequest.getLocation().getCopy();
+ }
+ } else if (request instanceof ChangeBoundsRequest) {
+ ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) request;
+ if (changeBoundsRequest.getLocation() != null) {
+ location = changeBoundsRequest.getLocation().getCopy();
+ }
+ }
+ return location;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ExecutionOperations.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ExecutionOperations.java
new file mode 100644
index 0000000000..4ef9286d72
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ExecutionOperations.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.command.IdentityCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.graphical.edit.policies.NodeCreationEditPolicy;
+import org.eclipse.sirius.diagram.graphical.edit.policies.SiriusGraphicalNodeEditPolicy;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.ReparentExecutionOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetMessageRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetVerticalRangeOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LostMessageEndEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceNodeCreationPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceSiriusGraphicalNodeEditPolicy;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.AirDefaultSizeNodeFigure;
+import org.eclipse.sirius.diagram.ui.tools.api.policy.CompoundEditPolicy;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.diagram.ui.tools.internal.util.EditPartQuery;
+
+/**
+ * Helper class to factor common code between root executions (lifelines) and
+ * normal executions which can not be shared by inheritance.
+ *
+ * @author pcdavid, smonnier
+ */
+public final class ExecutionOperations {
+ private ExecutionOperations() {
+ // Prevent instantiations.
+ }
+
+ /**
+ * Install/replace a NodeCreationEditPolicy on the CONTAINER_ROLE which is
+ * aware of the ExecutionCreationTool and calls it instead of the generic
+ * NodeCreationDescription.
+ *
+ * @param self
+ * the edit part.
+ */
+ public static void installExecutionAwareNodeCreationPolicy(ISequenceEventEditPart self) {
+ ExecutionOperations.replaceEditPolicy(self, EditPolicy.CONTAINER_ROLE, new SequenceNodeCreationPolicy(), NodeCreationEditPolicy.class);
+ ExecutionOperations.replaceEditPolicy(self, EditPolicy.GRAPHICAL_NODE_ROLE, new SequenceSiriusGraphicalNodeEditPolicy(), SiriusGraphicalNodeEditPolicy.class);
+ }
+
+ /**
+ * .
+ *
+ * @param self
+ * .
+ * @param role
+ * .
+ * @param editPolicy
+ * .
+ * @param policyType
+ * .
+ */
+ public static void replaceEditPolicy(IGraphicalEditPart self, String role, EditPolicy editPolicy, Class<?> policyType) {
+ if (self.getEditPolicy(role) instanceof CompoundEditPolicy) {
+ /*
+ * See
+ * AbstractDiagramNodeEditPartOperation.createDefaultEditPolicies
+ * (IAbstractDiagramNodeEditPart self) for the expected structure of
+ * the policy on CONTAINER_ROLE.
+ */
+ CompoundEditPolicy cep = (CompoundEditPolicy) self.getEditPolicy(role);
+ for (int i = 0; i < cep.getEditPolicies().size(); i++) {
+ if (policyType.isInstance(cep.getEditPolicies().get(i))) {
+ cep.getEditPolicies().set(i, editPolicy);
+ break;
+ }
+ }
+ self.installEditPolicy(role, cep);
+ } else {
+ self.installEditPolicy(role, editPolicy);
+ }
+
+ }
+
+ /**
+ * If possible, make the whole figure's area a valid location for a
+ * SlidableAnchor. Executions are usually very narrow vertically, and the
+ * default setting (0.5) makes the zone usable to anchor a message too small
+ * to be usable.
+ *
+ * @param figure
+ * the figure to adjust.
+ */
+ public static void adjustFigureSlidableArea(NodeFigure figure) {
+ if (figure instanceof AirDefaultSizeNodeFigure) {
+ ((AirDefaultSizeNodeFigure) figure).setSlidableAnchorArea(1.0);
+ }
+ }
+
+ /**
+ * Returns a command to reconnect any connection incident to the specified
+ * execution (which is about to be removed) to the parent of that execution
+ * while keeping the same vertical range.
+ *
+ * @param exec
+ * the execution which is about to be removed.
+ * @return a command to reconnect all the edges incident to that execution
+ * on its parent, while keeping the same vertical range.
+ */
+ public static org.eclipse.emf.common.command.Command getReconnectEdgesToParentCommand(ExecutionEditPart exec) {
+ org.eclipse.emf.common.command.CompoundCommand result = new org.eclipse.emf.common.command.CompoundCommand();
+
+ ISequenceEventEditPart parentEP = new EditPartQuery(exec).getFirstAncestorOfType(ISequenceEventEditPart.class);
+ AbstractNodeEvent execution = (AbstractNodeEvent) exec.getISequenceEvent();
+ ISequenceEvent parent = execution.getHierarchicalParentEvent();
+ Range parentRange = parent.getVerticalRange();
+
+ /**
+ * Previously, we assumed that the call/return messages of an execution
+ * will be deleted with it ; and GMF could be confused if they were
+ * reconnected (leaving invalid edit parts on the diagram, leading to a
+ * grey cross appearing which can not be removed except by
+ * closing/reopening the diagram).
+ * <p>
+ * This assumption was highly specific to a particular semantic of the
+ * delete tool associated with the execution. Now the reconnection is
+ * done before the call of the delete tool.
+ */
+
+ for (SequenceMessageEditPart msg : Iterables.filter(exec.getSourceConnections(), SequenceMessageEditPart.class)) {
+ if (msg.getSource() != msg.getTarget()) {
+ result.append(ExecutionOperations.getSourceReconnectionCommand(parentEP, parentRange, msg));
+ }
+ }
+ for (SequenceMessageEditPart msg : Iterables.filter(exec.getTargetConnections(), SequenceMessageEditPart.class)) {
+ if (msg.getSource() != msg.getTarget()) {
+ result.append(ExecutionOperations.getTargetReconnectionCommand(parentEP, parentRange, msg));
+ }
+ }
+ for (SequenceMessageEditPart msg : Iterables.filter(exec.getSourceConnections(), SequenceMessageEditPart.class)) {
+ Message message = (Message) msg.getISequenceEvent();
+ if (msg.getSource() == msg.getTarget()) {
+ result.append(ExecutionOperations.getReflectiveReconnectionCommand(parentEP.getISequenceEvent(), parentRange, message, parentEP.getEditingDomain()));
+ }
+ }
+
+ if (result.isEmpty()) {
+ return IdentityCommand.INSTANCE;
+ } else {
+ return result;
+ }
+ }
+
+ private static Command getReflectiveReconnectionCommand(ISequenceEvent parent, Range parentRange, Message msg, TransactionalEditingDomain domain) {
+ CompoundCommand result = new CompoundCommand();
+ Range currentRange = msg.getVerticalRange();
+
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation((Edge) msg.getNotationView(), currentRange, true);
+ // The source side is reconnected to the parent of the execution being
+ // deleted.
+ smrc.setSource(parent.getNotationView(), new Rectangle(0, parentRange.getLowerBound(), 0, parentRange.width()));
+ // The target side is reconnected to the parent of the execution being
+ // removed.
+ smrc.setTarget(parent.getNotationView(), new Rectangle(0, parentRange.getLowerBound(), 0, parentRange.width()));
+ result.append(CommandFactory.createRecordingCommand(domain, smrc));
+ return result;
+ }
+
+ private static Command getSourceReconnectionCommand(ISequenceEventEditPart parent, Range parentRange, SequenceMessageEditPart msg) {
+ CompoundCommand result = new CompoundCommand();
+ Range currentRange = msg.getISequenceEvent().getVerticalRange();
+
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation((Edge) msg.getNotationView(), currentRange, true);
+ // The source side is reconnected to the parent of the execution being
+ // deleted.
+ smrc.setSource(parent.getNotationView(), new Rectangle(0, parentRange.getLowerBound(), 0, parentRange.width()));
+ // The target side does not change but we need to compute its bounds and
+ // it may not be an ISequenceEvent (e.g. an InstanceRole)
+ IGraphicalEditPart target = (IGraphicalEditPart) msg.getTarget();
+ Rectangle targetBounds;
+ if (target instanceof ISequenceEventEditPart) {
+ Range targetRange = SequenceEditPartsOperations.getVerticalRange((ISequenceEventEditPart) target);
+ targetBounds = new Rectangle(0, targetRange.getLowerBound(), 0, targetRange.width());
+ } else {
+ targetBounds = target.getFigure().getBounds().getCopy();
+ if (target.getFigure().getParent() != null) {
+ target.getFigure().getParent().translateToAbsolute(targetBounds);
+ }
+ }
+ smrc.setTarget(target.getNotationView(), targetBounds);
+ result.append(CommandFactory.createRecordingCommand(parent.getEditingDomain(), smrc));
+ return result;
+ }
+
+ private static Command getTargetReconnectionCommand(ISequenceEventEditPart parent, Range parentRange, SequenceMessageEditPart msg) {
+ CompoundCommand result = new CompoundCommand();
+ Range currentRange = msg.getISequenceEvent().getVerticalRange();
+
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation((Edge) msg.getNotationView(), currentRange, true);
+ // The source side does not change but we need to compute its bounds.
+ IGraphicalEditPart source = (IGraphicalEditPart) msg.getSource();
+ Rectangle sourceBounds;
+ if (source instanceof ISequenceEventEditPart) {
+ Range sourceRange = SequenceEditPartsOperations.getVerticalRange((ISequenceEventEditPart) source);
+ sourceBounds = new Rectangle(0, sourceRange.getLowerBound(), 0, sourceRange.width());
+ } else if (source instanceof LostMessageEndEditPart) {
+ LostMessageEnd lostMessageEnd = ((LostMessageEndEditPart) source).getLostMessageEnd();
+ sourceBounds = lostMessageEnd.getProperLogicalBounds().getCopy();
+ } else {
+ throw new RuntimeException("The source of a message should always be an ISequenceEvent but was: " + String.valueOf(source));
+ }
+ smrc.setSource(source.getNotationView(), sourceBounds);
+ // The target side is reconnected to the parent of the execution being
+ // removed.
+ smrc.setTarget(parent.getNotationView(), new Rectangle(0, parentRange.getLowerBound(), 0, parentRange.width()));
+ result.append(CommandFactory.createRecordingCommand(parent.getEditingDomain(), smrc));
+ return result;
+ }
+
+ /**
+ * Returns a command to reconnect all the direct sub-executions of the
+ * specified execution (which is about to be removed) to the parent of that
+ * execution while keeping the same vertical range.
+ *
+ * @param removedExecEditPart
+ * the execution which is about to be removed.
+ * @return a command to reconnect all the direct sub-executions of that
+ * execution on its parent, while keeping the same vertical range.
+ */
+ public static org.eclipse.emf.common.command.Command getReconnectSubExecutionsToParentCommand(final ExecutionEditPart removedExecEditPart) {
+ org.eclipse.emf.common.command.CompoundCommand result = new org.eclipse.emf.common.command.CompoundCommand();
+
+ ISequenceEvent removedExec = removedExecEditPart.getISequenceEvent();
+ if (removedExec != null) {
+ ISequenceEvent futureParent = removedExec.getHierarchicalParentEvent();
+ TransactionalEditingDomain domain = removedExecEditPart.getEditingDomain();
+ for (View hierarchicalChild : Iterables.filter(Iterables.filter(removedExec.getNotationView().getChildren(), View.class), AbstractNodeEvent.notationPredicate())) {
+ Option<AbstractNodeEvent> child = ISequenceElementAccessor.getAbstractNodeEvent(hierarchicalChild);
+ if (child.some()) {
+ final Range childRange = child.get().getVerticalRange();
+ result.append(CommandFactory.createRecordingCommand(domain, new ReparentExecutionOperation(child.get(), futureParent)));
+ result.append(CommandFactory.createRecordingCommand(domain, new SetVerticalRangeOperation(child.get(), childRange)));
+ }
+ }
+ }
+ if (result.isEmpty()) {
+ return IdentityCommand.INSTANCE;
+ } else {
+ return result;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/MoveViewOperation.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/MoveViewOperation.java
new file mode 100644
index 0000000000..3f68b58f0e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/MoveViewOperation.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+
+/**
+ * Shift a view of a delta.
+ *
+ * @author edugueperoux
+ */
+public class MoveViewOperation extends AbstractModelChangeOperation<Void> {
+
+ private IAdaptable adapter;
+
+ private Point moveDelta;
+
+ /**
+ * Default constructor.
+ *
+ * @param label
+ * label to display in the undo menu item
+ * @param adapter
+ * adapter for the view
+ * @param moveDelta
+ * delta to move the view
+ */
+ public MoveViewOperation(String label, IAdaptable adapter, Point moveDelta) {
+ super(label);
+ Assert.isNotNull(adapter, "view cannot be null"); //$NON-NLS-1$
+ Assert.isNotNull(moveDelta, "moveDelta cannot be null"); //$NON-NLS-1$
+ this.adapter = adapter;
+ this.moveDelta = moveDelta;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ if (adapter != null) {
+ View view = (View) adapter.getAdapter(View.class);
+ if (moveDelta != null) {
+ if (view instanceof Node) {
+ Node node = (Node) view;
+ LayoutConstraint constraint = node.getLayoutConstraint();
+ if (constraint != null && NotationPackage.eINSTANCE.getLocation().isInstance(constraint)) {
+ Location location = (Location) constraint;
+ location.setX(location.getX() + moveDelta.x);
+ location.setY(location.getY() + moveDelta.y);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeMessagesOperation.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeMessagesOperation.java
new file mode 100644
index 0000000000..df13989be3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeMessagesOperation.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import java.util.Collection;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+
+/**
+ * This operation is called to shift the given messages. It adjusts the GMF
+ * bendpoints of the messages to/from an execution (or any of its
+ * sub-executions).
+ *
+ * @author mporhel
+ */
+public class ResizeMessagesOperation extends ShiftMessagesOperation {
+
+ private int resizeDelta;
+
+ /**
+ * Constructor.
+ *
+ * @param messagesToShift
+ * name of the current Operation.
+ * @param movedElements
+ * name of the current Operation.
+ * @param deltaY
+ * the vertical amount the execution was moved.
+ * @param revert
+ * if true, revert the adjustments from source/target vectors
+ * @param move
+ * if true, the messages of any of its sub-executions will be
+ * shifted. If false, the parent part was resized and only direct
+ * sub messages will be shifted
+ * @param resizeDelta
+ * the resize delta
+ */
+ public ResizeMessagesOperation(Collection<Message> messagesToShift, Collection<ISequenceEvent> movedElements, int deltaY, boolean revert, boolean move, int resizeDelta) {
+ super(messagesToShift, movedElements, deltaY, revert, move);
+ // this.resizeDelta = resizeDelta;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ShiftMessagesOperation#getDeltaY(org.eclipse.gmf.runtime.notation.Edge,
+ * boolean)
+ */
+ @Override
+ protected int getDeltaY(Edge edge, boolean source) {
+ return super.getDeltaY(edge, source) + resizeDelta;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeViewOperation.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeViewOperation.java
new file mode 100644
index 0000000000..12faa8316a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ResizeViewOperation.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.Size;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+
+/**
+ * Resize a view of a delta.
+ *
+ * @author edugueperoux
+ */
+public class ResizeViewOperation extends AbstractModelChangeOperation<Void> {
+
+ private IAdaptable adapter;
+
+ private Dimension sizeDelta;
+
+ /**
+ * Default constructor.
+ *
+ * @param label
+ * label to display in the undo menu item
+ * @param adapter
+ * adapter for the view
+ * @param sizeDelta
+ * delta to resize the view
+ */
+ public ResizeViewOperation(String label, IAdaptable adapter, Dimension sizeDelta) {
+ super(label);
+ Assert.isNotNull(adapter, "view cannot be null"); //$NON-NLS-1$
+ Assert.isNotNull(sizeDelta, "sizeDelta cannot be null"); //$NON-NLS-1$
+ this.adapter = adapter;
+ this.sizeDelta = sizeDelta;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ if (adapter != null) {
+ View view = (View) adapter.getAdapter(View.class);
+ if (sizeDelta != null) {
+ if (view instanceof Node) {
+ Node node = (Node) view;
+ LayoutConstraint constraint = node.getLayoutConstraint();
+ if (constraint != null && NotationPackage.eINSTANCE.getSize().isInstance(constraint)) {
+ Size size = (Size) constraint;
+ size.setWidth(size.getWidth() + sizeDelta.width);
+ size.setHeight(size.getHeight() + sizeDelta.height);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/SequenceEditPartsOperations.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/SequenceEditPartsOperations.java
new file mode 100644
index 0000000000..ea58ebd4be
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/SequenceEditPartsOperations.java
@@ -0,0 +1,367 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.requests.CreateConnectionRequest;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.description.tool.EdgeCreationDescription;
+import org.eclipse.sirius.diagram.internal.view.factories.ViewLocationHint;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshGraphicalOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshSemanticOrderingsOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SynchronizeISequenceEventsSemanticOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SynchronizeInstanceRoleSemanticOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.tool.ToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.description.tool.MessageCreationTool;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.command.GMFCommandWrapper;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+
+/**
+ * Helper class to share code between different kinds of edit parts when
+ * inheritance is not possible or inconvenient.
+ *
+ * @author pcdavid, smonnier, mporhel
+ */
+public final class SequenceEditPartsOperations {
+ private SequenceEditPartsOperations() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Add graphical and semantic synchronize commands to do a full refresh of
+ * the semantic and graphical orderings.
+ *
+ * @param self
+ * the edit part which created the base command.
+ * @param cc
+ * the compound command to complete.
+ */
+ public static void appendFullRefresh(IGraphicalEditPart self, CompoundCommand cc) {
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(self);
+ SequenceDDiagram sequenceDDiagram = sequenceDiagram.getSequenceDDiagram();
+ TransactionalEditingDomain domain = self.getEditingDomain();
+ cc.add(new ICommandProxy(CommandFactory.createICommand(domain, new RefreshGraphicalOrderingOperation(sequenceDiagram))));
+ cc.add(new ICommandProxy(CommandFactory.createICommand(domain, new RefreshSemanticOrderingsOperation(sequenceDDiagram))));
+ }
+
+ /**
+ * Add graphical and semantic synchronize commands to do a full refresh of
+ * the semantic and graphical orderings.
+ *
+ * @param self
+ * the edit part which created the base command.
+ * @param ctc
+ * the CompositeTransactionalCommand to complete.
+ */
+ public static void appendFullRefresh(IGraphicalEditPart self, CompositeTransactionalCommand ctc) {
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(ctc, self);
+ }
+
+ /**
+ * Append a command to refresh the graphical ordering of the sequence
+ * diagram containing the specified edit part.
+ *
+ * @param cc
+ * the target CompositeTransactionalCommand.
+ * @param self
+ * an edit part of the sequence diagram to refresh.
+ */
+ public static void addRefreshGraphicalOrderingCommand(CompositeTransactionalCommand cc, IGraphicalEditPart self) {
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(self);
+ TransactionalEditingDomain domain = cc.getEditingDomain();
+ cc.compose(CommandFactory.createICommand(domain, new RefreshGraphicalOrderingOperation(sequenceDiagram)));
+ }
+
+ /**
+ * Append a command to refresh the semantic ordering of a sequence diagram.
+ *
+ * @param cc
+ * the target CompositeTransactionalCommand.
+ * @param self
+ * an edit part of the sequence diagram to refresh.
+ */
+ public static void addRefreshSemanticOrderingCommand(CompositeTransactionalCommand cc, IGraphicalEditPart self) {
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(self);
+ SequenceDDiagram sequenceDDiagram = sequenceDiagram.getSequenceDDiagram();
+ TransactionalEditingDomain domain = cc.getEditingDomain();
+ cc.compose(CommandFactory.createICommand(domain, new RefreshSemanticOrderingsOperation(sequenceDDiagram)));
+ }
+
+ /**
+ * Append a command to synchronize the semantic ordering of the specified
+ * event.
+ *
+ * @param cc
+ * the target CompositeTransactionalCommand.
+ * @param event
+ * the event which has moved graphically and whose semantic
+ * ordering should be updated to match the new position.
+ * @param set
+ */
+ public static void addSynchronizeSemanticOrderingCommand(CompositeTransactionalCommand cc, ISequenceEvent event) {
+ cc.compose(CommandFactory.createICommand(cc.getEditingDomain(), new SynchronizeISequenceEventsSemanticOrderingOperation(event)));
+ }
+
+ /**
+ * Append a command to synchronize the semantic ordering of the specified
+ * event.
+ *
+ * @param cc
+ * the target CompositeTransactionalCommand.
+ * @param event
+ * the event which has moved graphically and whose semantic
+ * ordering should be updated to match the new position.
+ * @param selection
+ * additionnal events to reorder.
+ */
+ public static void addSynchronizeSemanticOrderingCommand(CompositeTransactionalCommand cc, ISequenceEvent event, Collection<ISequenceEvent> selection) {
+ cc.compose(CommandFactory.createICommand(cc.getEditingDomain(), new SynchronizeISequenceEventsSemanticOrderingOperation(event, selection)));
+ }
+
+ /**
+ * Append a command to synchronize the semantic ordering of the specified
+ * event.
+ *
+ * @param cc
+ * the target CompositeTransactionalCommand.
+ * @param instanceRole
+ * the instance role which has moved graphically and whose
+ * semantic ordering should be updated to match the new position.
+ * @param set
+ */
+ public static void addSynchronizeSemanticOrderingCommand(CompositeTransactionalCommand cc, InstanceRole instanceRole) {
+ cc.compose(CommandFactory.createICommand(cc.getEditingDomain(), new SynchronizeInstanceRoleSemanticOrderingOperation(instanceRole)));
+ }
+
+ /**
+ * Append a command to synchronize the semantic ordering of the specified
+ * event.
+ *
+ * @param cc
+ * the target CompositeTransactionalCommand.
+ * @param instanceRole
+ * the instance role which has moved graphically and whose
+ * semantic ordering should be updated to match the new position.
+ * @param selection
+ * additionnal instance roles to reorder.
+ */
+ public static void addSynchronizeSemanticOrderingCommand(CompositeTransactionalCommand cc, InstanceRole instanceRole, Collection<InstanceRole> selection) {
+ cc.compose(CommandFactory.createICommand(cc.getEditingDomain(), new SynchronizeInstanceRoleSemanticOrderingOperation(instanceRole, selection)));
+ }
+
+ /**
+ * Registers an edit part in the viewer's registry using the specified
+ * <code>DDiagramElement</code> of <code>DDiagram</code> as key.
+ *
+ * @param self
+ * the edit part to register.
+ * @param element
+ * the key to use.
+ */
+ @SuppressWarnings("unchecked")
+ public static void registerDiagramElement(IGraphicalEditPart self, EObject element) {
+ self.getViewer().getEditPartRegistry().put(element, self);
+ }
+
+ /**
+ * Unregisters an edit part in the viewer's registry using the specified
+ * <code>DDiagramElement</code> of <code>DDiagram</code> as key.
+ *
+ * @param self
+ * the edit part to unregister.
+ * @param element
+ * the key of the registry entry to remove.
+ */
+ public static void unregisterDiagramElement(IGraphicalEditPart self, EObject element) {
+ @SuppressWarnings("unchecked")
+ Map<Object, Object> registry = self.getViewer().getEditPartRegistry();
+ if (registry.get(element) == self) {
+ registry.remove(element);
+ }
+ }
+
+ /**
+ * Configures a bordered node to appear on the given side and at the given
+ * offset of its parent part.
+ *
+ * @param self
+ * the bordered node.
+ * @param side
+ * the side of the parent on which the node should be.
+ * @param offset
+ * the offset (relative to the parent) at which the node should
+ * be placed.
+ */
+ public static void setBorderItemLocation(AbstractBorderItemEditPart self, int side, Dimension offset) {
+ IBorderItemLocator borderItemLocator = self.getBorderItemLocator();
+ if (borderItemLocator instanceof DBorderItemLocator) {
+ DBorderItemLocator dbil = (DBorderItemLocator) borderItemLocator;
+ dbil.setCurrentSideOfParent(side);
+ dbil.setBorderItemOffset(offset);
+ }
+ }
+
+ /**
+ * Shared implementation of most of
+ * SiriusBaseItemSemanticEditPolicy.buildCreateEdgeCommand() for use in
+ * ExecutionSemanticEditPolicy and InstanceRoleSemanticEditPolicy.
+ *
+ * @param self
+ * the edit part.
+ * @param result
+ * the command to modify.
+ * @param request
+ * the original request.
+ * @param source
+ * the source of the edge to create.
+ * @param target
+ * the target of the edge to create.
+ * @param edgeCreationDescription
+ * the tool to use to create the edge.
+ * @param cmdFactoryProvider
+ * the command factory provider to use to build a command from
+ * the tool.
+ */
+ public static void buildCreateEdgeCommand(IGraphicalEditPart self, CompoundCommand result, CreateConnectionRequest request, EdgeTarget source, EdgeTarget target,
+ EdgeCreationDescription edgeCreationDescription, IDiagramCommandFactoryProvider cmdFactoryProvider) {
+ org.eclipse.emf.common.command.Command emfCommand;
+ TransactionalEditingDomain domain = self.getEditingDomain();
+ if (edgeCreationDescription instanceof MessageCreationTool && ((DDiagramElement) source).getParentDiagram() instanceof SequenceDDiagram) {
+ Point sourceLocation = request.getLocation().getCopy();
+ Point targetLocation = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(sourceLocation, self);
+ GraphicalHelper.screen2logical(targetLocation, self);
+
+ Point srcLocationHint = SequenceEditPartsOperations.getConnectionSourceLocation(request, self);
+ Point tgtLocationHint = SequenceEditPartsOperations.getConnectionTargetLocation(request, self);
+
+ if (srcLocationHint != null) {
+ sourceLocation = srcLocationHint;
+ }
+
+ if (tgtLocationHint != null) {
+ targetLocation = tgtLocationHint;
+ }
+
+ // Avoid deferred message, accept only messageToSelf
+ if (source != target) {
+ targetLocation = sourceLocation;
+ }
+
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(self);
+ SequenceDDiagram diagram = sequenceDiagram.getSequenceDDiagram();
+ EventEnd startingEndBefore = SequenceGraphicalHelper.getEndBefore(diagram, sourceLocation.y);
+ EventEnd finishingEndBefore = SequenceGraphicalHelper.getEndBefore(diagram, targetLocation.y);
+ emfCommand = ToolCommandBuilder.buildCreateMessageCommand(source, target, (MessageCreationTool) edgeCreationDescription, startingEndBefore, finishingEndBefore);
+
+ org.eclipse.emf.common.command.CompoundCommand cc = new org.eclipse.emf.common.command.CompoundCommand();
+ cc.append(emfCommand);
+ cc.append(CommandFactory.createRecordingCommand(domain, new RefreshSemanticOrderingsOperation(diagram)));
+ emfCommand = cc;
+ } else {
+ emfCommand = cmdFactoryProvider.getCommandFactory(domain).buildCreateEdgeCommandFromTool(source, target, edgeCreationDescription);
+ }
+ result.add(new ICommandProxy(new GMFCommandWrapper(domain, emfCommand)));
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#getVerticalRange()}.
+ *
+ * @param self
+ * the event.
+ * @return the maximal range occupied by children of the event.
+ */
+ public static Range getVerticalRange(ISequenceEventEditPart self) {
+ ISequenceEvent iSequenceEvent = self != null ? self.getISequenceEvent() : null;
+ return iSequenceEvent != null ? iSequenceEvent.getVerticalRange() : Range.emptyRange();
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange()}.
+ *
+ * @param self
+ * the event.
+ * @param newRange
+ * the new range
+ */
+ public static void setVerticalRange(ISequenceEventEditPart self, Range newRange) {
+ ISequenceEvent iSequenceEvent = self != null ? self.getISequenceEvent() : null;
+ if (iSequenceEvent != null) {
+ iSequenceEvent.setVerticalRange(newRange);
+ }
+ }
+
+ /**
+ * Return the source connection anchor location from view location hint.
+ *
+ * @param request
+ * the current request.
+ * @param self
+ * an edit part to compute logical location.
+ * @return the source location.
+ */
+ public static Point getConnectionSourceLocation(CreateConnectionRequest request, IGraphicalEditPart self) {
+ return SequenceEditPartsOperations.getConnectionLocation(self, ViewLocationHint.SOURCE_ANCHOR_LOCATION);
+ }
+
+ /**
+ * Return the target connection anchor location from view location hint.
+ *
+ * @param request
+ * the current request.
+ * @param self
+ * an edit part to compute logical location.
+ * @return the target location.
+ */
+ public static Point getConnectionTargetLocation(CreateConnectionRequest request, IGraphicalEditPart self) {
+ return SequenceEditPartsOperations.getConnectionLocation(self, ViewLocationHint.TARGET_ANCHOR_LOCATION);
+ }
+
+ private static Point getConnectionLocation(IGraphicalEditPart self, String key) {
+ Object hint = ViewLocationHint.getInstance().getData(key);
+ if (hint instanceof Point) {
+ Point location = ((Point) hint).getCopy();
+ GraphicalHelper.screen2logical(location, self);
+ return location;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftDescendantMessagesOperation.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftDescendantMessagesOperation.java
new file mode 100644
index 0000000000..7b0dee2f8c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftDescendantMessagesOperation.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
+import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ISequenceEventsTreeIterator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.util.GMFNotationHelper;
+
+/**
+ * This operation is called when an execution is moved or resized vertically. It
+ * adjusts the GMF bendpoints of the messages to/from an execution (or any of
+ * its sub-executions) so that the messages are moved along with the execution
+ * of the same amount.
+ *
+ * @author pcdavid, mporhel, smonnier
+ */
+public class ShiftDescendantMessagesOperation extends ShiftMessagesOperation {
+ private ISequenceEvent parent;
+
+ private final boolean fromTop;
+
+ /**
+ * Used for execution reparent.
+ */
+ private boolean ignoreContainedReflexiveMessage;
+
+ private Range oldParentRange;
+
+ private Range newParentRange;
+
+ private ISequenceEvent finalGrandParent;
+
+ /**
+ * Constructor to shift all sub messages after move.
+ *
+ * @param parent
+ * the execution whose descendant messages must be adjusted.
+ * @param deltaY
+ * the vertical amount the execution was moved.
+ */
+ public ShiftDescendantMessagesOperation(ISequenceEvent parent, int deltaY) {
+ this(parent, deltaY, false, true, true);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parent
+ * the execution whose descendant messages must be adjusted.
+ * @param deltaY
+ * the vertical amount the execution was moved.
+ * @param revert
+ * if true, revert the adjustments from source/target vectors
+ * @param move
+ * if true, the messages of any of its sub-executions will be
+ * shifted. If false, the parent part was resized and only direct
+ * sub messages will be shifted
+ * @param fromTop
+ * Used if move = false (resize) to know from where the
+ * parentPart is resized.
+ */
+ public ShiftDescendantMessagesOperation(ISequenceEvent parent, int deltaY, boolean revert, boolean move, boolean fromTop) {
+ super("Shift sub-messages bendpoints by " + deltaY, deltaY, revert, move);
+ this.parent = parent;
+ this.fromTop = fromTop;
+ this.oldParentRange = parent.getVerticalRange();
+ this.newParentRange = getNewParentRange();
+ this.finalGrandParent = null;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parent
+ * the execution whose descendant messages must be adjusted.
+ * @param finalGrandParent
+ * the actual grandparent of the "executionEditPart" replacement
+ * (after a refresh) at the time of command execution.
+ * @param deltaY
+ * the vertical amount the execution was moved.
+ * @param ignoreContainedReflexiveMessage
+ * the parameter to decide if we need to ignore the contained
+ * reflexive messages.
+ */
+ public ShiftDescendantMessagesOperation(ISequenceEvent parent, ISequenceEvent finalGrandParent, int deltaY, boolean ignoreContainedReflexiveMessage) {
+ this(parent, deltaY);
+ this.finalGrandParent = finalGrandParent;
+ this.ignoreContainedReflexiveMessage = ignoreContainedReflexiveMessage;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ final Set<ISequenceEvent> descendants = Sets.newHashSet();
+ populateMessageToShift(descendants);
+
+ // Handle messages.
+ super.execute();
+
+ // Handle notes.
+ Set<Edge> allConnections = Sets.newHashSet();
+
+ Iterator<ISequenceEvent> iter = new ISequenceEventsTreeIterator(parent, true);
+ while (iter.hasNext()) {
+ ISequenceEvent iSequenceEvent = iter.next();
+ populateConnections(allConnections, iSequenceEvent.getNotationView());
+ }
+
+ for (Edge conn : allConnections) {
+ if (!descendants.contains(conn) && (isNoteAttachment(conn) || isNonSequenceEdgeAttachment(conn))) {
+ shiftAnchor(conn);
+ }
+ }
+ return null;
+ }
+
+ private void populateMessageToShift(Set<ISequenceEvent> descendants) {
+ if (finalGrandParent != null) {
+ final View model = parent.getNotationView();
+ for (final ISequenceEvent child : finalGrandParent.getSubEvents()) {
+ if (child.getNotationView() == model) {
+ parent = child;
+ break;
+ }
+ }
+ }
+
+ populate(descendants);
+
+ final Predicate<Message> filterReflexiveMessage = new Predicate<Message>() {
+ public boolean apply(final Message input) {
+ return !input.isReflective();
+ }
+ };
+
+ if (ignoreContainedReflexiveMessage) {
+ Iterables.addAll(messagesToShift, Iterables.filter(Iterables.filter(descendants, Message.class), filterReflexiveMessage));
+ } else {
+ Iterables.addAll(messagesToShift, Iterables.filter(descendants, Message.class));
+ }
+ }
+
+ private void populateConnections(Set<Edge> allConnections, View part) {
+ Iterables.addAll(allConnections, Iterables.filter(part.getSourceEdges(), Edge.class));
+ Iterables.addAll(allConnections, Iterables.filter(part.getTargetEdges(), Edge.class));
+ }
+
+ private boolean isNoteAttachment(Edge conn) {
+ return conn != null && GMFNotationHelper.isNoteAttachment(conn);
+ }
+
+ private boolean isNonSequenceEdgeAttachment(Edge conn) {
+ return conn != null && conn.getElement() instanceof DEdge && !ISequenceElementAccessor.getMessage(conn).some();
+ }
+
+ private void shiftAnchor(Edge edge) {
+ boolean isOutgoing = Iterables.contains(Iterables.transform(movedElements, ISequenceElement.NOTATION_VIEW), edge.getSource());
+
+ if (isOutgoing) {
+ IdentityAnchor sourceAnchor = (IdentityAnchor) edge.getSourceAnchor();
+ int sourceAnchorLocation = SequenceGraphicalHelper.getAnchorAbsolutePosition(sourceAnchor, oldParentRange);
+ PrecisionPoint position = BaseSlidableAnchor.parseTerminalString(sourceAnchor.getId());
+ position.preciseY = newParentRange.getProportionalLocation(sourceAnchorLocation);
+ String terminal = new SlidableAnchor(null, position).getTerminal();
+ sourceAnchor.setId(terminal);
+ } else {
+ IdentityAnchor targetAnchor = (IdentityAnchor) edge.getTargetAnchor();
+ int targetAnchorLocation = SequenceGraphicalHelper.getAnchorAbsolutePosition(targetAnchor, oldParentRange);
+ PrecisionPoint position = BaseSlidableAnchor.parseTerminalString(targetAnchor.getId());
+ position.preciseY = newParentRange.getProportionalLocation(targetAnchorLocation);
+ String terminal = new SlidableAnchor(null, position).getTerminal();
+ targetAnchor.setId(terminal);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected int getDeltaY(Edge edge, boolean source) {
+ if (!move) {
+ IdentityAnchor anchor;
+ if (source) {
+ anchor = (IdentityAnchor) edge.getSourceAnchor();
+ } else {
+ anchor = (IdentityAnchor) edge.getTargetAnchor();
+ }
+ return getDeltaY(anchor);
+ } else {
+ return super.getDeltaY(edge, source);
+ }
+ }
+
+ private int getDeltaY(IdentityAnchor anchor) {
+ double oldAnchorLocation = SequenceGraphicalHelper.getAnchorAbsolutePosition(anchor, oldParentRange);
+ double newAnchorLocation = SequenceGraphicalHelper.getAnchorAbsolutePosition(anchor, newParentRange);
+ return (int) (oldAnchorLocation - newAnchorLocation);
+ }
+
+ private void populate(Set<ISequenceEvent> descendants) {
+ if (move) {
+ descendants.addAll(new ISequenceEventQuery(parent).getAllDescendants(true));
+ Iterables.addAll(movedElements, Iterables.filter(descendants, AbstractNodeEvent.class));
+ } else {
+ // descendants.addAll(parent.getSubEvents());
+ descendants.addAll(new ISequenceEventQuery(parent).getAllDescendants(true));
+ movedElements.add(parent);
+ }
+ // Finds compounds events of each ExecutionEditPart found in descendants
+ ArrayList<ISequenceEvent> compoundEvents = Lists.newArrayList();
+ for (AbstractNodeEvent eep : Iterables.filter(descendants, AbstractNodeEvent.class)) {
+ compoundEvents.addAll(EventEndHelper.getCompoundEvents(eep));
+ }
+ Iterables.addAll(descendants, compoundEvents);
+ if (parent instanceof Lifeline) {
+ movedElements.add(parent);
+ }
+ }
+
+ private Range getNewParentRange() {
+ int newLowerBound = oldParentRange.getLowerBound();
+ int newUppeRBound = oldParentRange.getUpperBound();
+ if (move) {
+ newLowerBound += deltaY;
+ newUppeRBound += deltaY;
+ } else if (fromTop) {
+ newLowerBound += deltaY;
+ } else {
+ newUppeRBound += deltaY;
+ }
+ return new Range(newLowerBound, newUppeRBound);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftMessagesOperation.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftMessagesOperation.java
new file mode 100644
index 0000000000..fb6b4091cc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/operation/ShiftMessagesOperation.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+
+/**
+ * This operation is called to shift the given messages. It adjusts the GMF
+ * bendpoints of the messages to/from an execution (or any of its
+ * sub-executions).
+ *
+ * @author mporhel
+ */
+public class ShiftMessagesOperation extends AbstractModelChangeOperation<Void> {
+ /**
+ * Indicates if messages to shift did really move.
+ */
+ protected final boolean move;
+
+ /**
+ * Message to shift.
+ */
+ protected final Collection<Message> messagesToShift = Lists.newArrayList();
+
+ /**
+ * Moved elements.
+ */
+ protected final Collection<ISequenceEvent> movedElements = Sets.newHashSet();
+
+ /**
+ * Vertical move to handle.
+ */
+ protected final int deltaY;
+
+ private final boolean revert;
+
+ /**
+ * Constructor.
+ *
+ * @param name
+ * name of the current Operation.
+ * @param deltaY
+ * the vertical amount the execution was moved.
+ * @param revert
+ * if true, revert the adjustments from source/target vectors
+ * @param move
+ * if true, the messages of any of its sub-executions will be
+ * shifted. If false, the parent part was resized and only direct
+ * sub messages will be shifted
+ */
+ protected ShiftMessagesOperation(String name, int deltaY, boolean revert, boolean move) {
+ super(name);
+ this.deltaY = deltaY;
+ this.revert = revert;
+ this.move = move;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param messagesToShift
+ * name of the current Operation.
+ * @param movedElements
+ * name of the current Operation.
+ * @param deltaY
+ * the vertical amount the execution was moved.
+ * @param revert
+ * if true, revert the adjustments from source/target vectors
+ * @param move
+ * if true, the messages of any of its sub-executions will be
+ * shifted. If false, the parent part was resized and only direct
+ * sub messages will be shifted
+ */
+ public ShiftMessagesOperation(Collection<Message> messagesToShift, Collection<ISequenceEvent> movedElements, int deltaY, boolean revert, boolean move) {
+ this("Shift given message", deltaY, revert, move);
+ Preconditions.checkNotNull(messagesToShift);
+ Preconditions.checkNotNull(movedElements);
+ this.messagesToShift.addAll(messagesToShift);
+ this.movedElements.addAll(movedElements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ for (Message smep : messagesToShift) {
+ shiftBendpoints(smep);
+ }
+
+ return null;
+ }
+
+ private void shiftBendpoints(Message message) {
+ boolean needShiftFromSrc = needShift(message, true);
+ boolean needShiftFromTgt = needShift(message, false);
+
+ Edge edge = (Edge) message.getNotationView();
+ int currentSourceDeltaY = 0;
+ int currentTargetDeltaY = 0;
+
+ /*
+ * If the message starts from the execution being moved (or any of its
+ * sub-executions), its sourceX/sourceY vectors are still valid as they
+ * are relative to the source anchor which moved along with the
+ * execution. However, the target execution/lifeline on the other side
+ * did not move, so we need to adjust the target vector.
+ */
+
+ /*
+ * The current message is moved by its target, so we need to adjust the
+ * source vector.
+ */
+ int srcShift = getDeltaY(edge, false);
+ if (needShiftFromSrc) {
+ currentSourceDeltaY = revert ? 0 : srcShift;
+ currentTargetDeltaY = revert ? srcShift : 0;
+ }
+ /*
+ * The current message is moved by its source, so we need to adjust the
+ * target vector.
+ */
+ int tgtShift = getDeltaY(edge, true);
+ if (needShiftFromTgt) {
+ currentTargetDeltaY = revert ? currentTargetDeltaY : tgtShift;
+ currentSourceDeltaY = revert ? tgtShift : currentSourceDeltaY;
+ }
+
+ RelativeBendpoints bp = (RelativeBendpoints) edge.getBendpoints();
+ List<?> oldPoints = bp.getPoints();
+ List<RelativeBendpoint> newPoints = Lists.newArrayList();
+ for (int i = 0; i < oldPoints.size(); i++) {
+ RelativeBendpoint old = (RelativeBendpoint) oldPoints.get(i);
+ newPoints.add(new RelativeBendpoint(old.getSourceX(), old.getSourceY() + currentSourceDeltaY, old.getTargetX(), old.getTargetY() + currentTargetDeltaY));
+ }
+ bp.setPoints(newPoints);
+ }
+
+ /**
+ * Check the direction of the given Message regarding the current context.
+ *
+ * @param message
+ * the message to check.
+ * @return true if the given message source lifeline is the actual context
+ * lifeline.
+ */
+ private boolean needShift(Message message, boolean source) {
+ boolean movedBySrc = movedElements.contains(message.getSourceElement());
+ boolean movedByTgt = movedElements.contains(message.getTargetElement());
+ boolean moved = movedBySrc || movedByTgt;
+
+ if (move && !revert) {
+ moved = moved || movedElements.contains(message);
+ }
+
+ boolean shiftedEnd = source ? !movedBySrc : !movedByTgt;
+ boolean reverted = revert && movedBySrc && movedByTgt;
+
+ return moved && (shiftedEnd || reverted);
+ }
+
+ /**
+ * Get deltaY for the request end of the current edge.
+ *
+ * @param edge
+ * the given edge.
+ * @param source
+ * the requested end.
+ * @return the deltaY.
+ */
+ protected int getDeltaY(Edge edge, boolean source) {
+ return deltaY;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/AbstractSequenceBorderedEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/AbstractSequenceBorderedEditPart.java
new file mode 100644
index 0000000000..0469ae3671
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/AbstractSequenceBorderedEditPart.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.RequestConstants;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gef.requests.DropRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editpolicies.EditPolicyRoles;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.internal.edit.parts.DNode2EditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ConnectionAnchorOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ExecutionOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.ExecutionSemanticEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * Special edit part for common behavior of Lifelines, Executions and States.
+ * They are treated as bordered nodes.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractSequenceBorderedEditPart extends DNode2EditPart implements ISequenceEventEditPart {
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public AbstractSequenceBorderedEditPart(final View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * Overridden to install a custom semantic edit policy and node creation
+ * policy.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+ installEditPolicy(EditPolicyRoles.SEMANTIC_ROLE, new ExecutionSemanticEditPolicy());
+ ExecutionOperations.installExecutionAwareNodeCreationPolicy(this);
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * Overridden to make the whole figure's area a valid location for a
+ * SlidableAnchor. Executions are usually very narrow vertically, and the
+ * default setting makes the zone usable to anchor a message too small to be
+ * usable.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createMainFigure() {
+ NodeFigure figure = super.createMainFigure();
+ ExecutionOperations.adjustFigureSlidableArea(figure);
+ return figure;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getSourceConnectionAnchor(Request request) {
+ ConnectionAnchor anchor = super.getSourceConnectionAnchor(request);
+ if (new RequestQuery(request).isSequenceMessageCreation()) {
+ anchor = ConnectionAnchorOperation.getSourceConnectionAnchor(this, request, anchor);
+ }
+ return anchor;
+ }
+
+ /**
+ * Use the same y location as the corresponding source connection anchor,
+ * stored in ViewLocationHint, to improve user feedback.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getTargetConnectionAnchor(Request request) {
+ boolean sequenceMessageCreation = new RequestQuery(request).isSequenceMessageCreation();
+ if (sequenceMessageCreation && request instanceof DropRequest) {
+ ConnectionAnchorOperation.matchRequestYLocationWithSourceAnchor((DropRequest) request);
+ }
+
+ ConnectionAnchor anchor = super.getTargetConnectionAnchor(request);
+
+ if (sequenceMessageCreation) {
+ anchor = ConnectionAnchorOperation.getTargetConnectionAnchor(this, request, anchor);
+ }
+ return anchor;
+ }
+
+ /**
+ * Overridden to have execution creation on existing execution and in same
+ * range of child execution, redirected to the most nested child execution.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPart getTargetEditPart(Request request) {
+ Set<String> retargetTypes = Sets.newHashSet(RequestConstants.REQ_CREATE, RequestConstants.REQ_CONNECTION_START, RequestConstants.REQ_CONNECTION_END);
+ if (retargetTypes.contains(request.getType()) && request instanceof CreateRequest) {
+ CreateRequest createRequest = (CreateRequest) request;
+ Point location = createRequest.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, this);
+ Range insertionPoint = new Range(location.y, location.y);
+ ISequenceEvent sequenceEvent = getISequenceEvent();
+ EventFinder eventFinder = new EventFinder(sequenceEvent, sequenceEvent.getLifeline().get());
+ ISequenceEvent mostSpecificSequenceEvent = eventFinder.findMostSpecificEvent(insertionPoint);
+
+ if (mostSpecificSequenceEvent instanceof AbstractNodeEvent && !sequenceEvent.equals(mostSpecificSequenceEvent)) {
+ Map<?, ?> editPartRegistry = getTopGraphicEditPart().getViewer().getEditPartRegistry();
+ Object obj = editPartRegistry.get(mostSpecificSequenceEvent.getNotationView());
+ if (obj instanceof ExecutionEditPart) {
+ ExecutionEditPart targetEditPart = (ExecutionEditPart) obj;
+ return targetEditPart;
+ }
+ }
+ }
+ return super.getTargetEditPart(request);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentCompartmentEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentCompartmentEditPart.java
new file mode 100644
index 0000000000..40a10c9818
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentCompartmentEditPart.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutAnimator;
+import org.eclipse.draw2d.MarginBorder;
+import org.eclipse.draw2d.ScrollPane;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.figures.ResizableCompartmentFigure;
+import org.eclipse.gmf.runtime.diagram.ui.figures.ShapeCompartmentFigure;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerViewNodeContainerCompartmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.CombinedFragmentInvisibleResizableCompartmentFigure;
+
+/**
+ * A specific DNodeContainerViewNodeContainerCompartmentEditPart to remove the
+ * scroll bars.
+ *
+ * @author smonnier
+ */
+public class CombinedFragmentCompartmentEditPart extends DNodeContainerViewNodeContainerCompartmentEditPart {
+ /**
+ * The visual ID. Same as a normal container compartment.
+ *
+ * @see DNodeContainerViewNodeContainerCompartmentEditPart.VISUAL_ID.
+ */
+ public static final int VISUAL_ID = 7001;
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view <code>controlled</code> by this edit part.
+ */
+ public CombinedFragmentCompartmentEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on combined fragment.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (!EditPolicy.CONTAINER_ROLE.equals(key)) {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * Overridden to remove the scroll bars.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public IFigure createFigure() {
+ ShapeCompartmentFigure scf = new CombinedFragmentInvisibleResizableCompartmentFigure(getCompartmentName(), getMapMode());
+ // Remove the shadow border to avoid unwanted spacing
+ scf.setBorder(null);
+ scf.getContentPane().setLayoutManager(getLayoutManager());
+ scf.getContentPane().addLayoutListener(LayoutAnimator.getDefault());
+ scf.setTitleVisibility(false);
+ scf.setToolTip((IFigure) null);
+ scf.getScrollPane().setHorizontalScrollBarVisibility(ScrollPane.NEVER);
+ scf.getScrollPane().setVerticalScrollBarVisibility(ScrollPane.NEVER);
+ return scf;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.editparts.ResizableCompartmentEditPart#refreshVisuals()
+ */
+ protected void refreshVisuals() {
+ super.refreshVisuals();
+
+ // TODO: Remove this when Sequence will be based on generic region
+ // support.
+ if (getFigure() instanceof ResizableCompartmentFigure) {
+ ResizableCompartmentFigure rcf = (ResizableCompartmentFigure) getFigure();
+ if (rcf.getScrollPane() != null) {
+ int mb = getMapMode().DPtoLP(0);
+ rcf.getScrollPane().setBorder(new MarginBorder(mb, mb, mb, mb));
+ }
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentEditPart.java
new file mode 100644
index 0000000000..363a1c13b9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/CombinedFragmentEditPart.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.FlatContainerStyle;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.CombinedFragmentResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+
+/**
+ * Special edit part for combined fragments.
+ *
+ * @author pcdavid
+ */
+public class CombinedFragmentEditPart extends DNodeContainerEditPart implements ISequenceEventEditPart {
+ /**
+ * Standard constructor, as expected by GMF.
+ *
+ * @param view
+ * the view.
+ */
+ public CombinedFragmentEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on combined fragment.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.PRIMARY_DRAG_ROLE.equals(key)) {
+ super.installEditPolicy(key, new CombinedFragmentResizableEditPolicy());
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createMainFigure() {
+ NodeFigure figure = super.createMainFigure();
+ // Remove the shadow border to avoid unwanted spacing
+ figure.setBorder(null);
+ forceCombinedFragmentDefaultSize(figure);
+ return figure;
+ }
+
+ private void forceCombinedFragmentDefaultSize(NodeFigure figure) {
+ if (figure instanceof DefaultSizeNodeFigure) {
+ EObject eObj = this.resolveSemanticElement();
+ if (eObj instanceof DDiagramElementContainer) {
+ DDiagramElementContainer container = (DDiagramElementContainer) eObj;
+ if (container.getOwnedStyle() instanceof FlatContainerStyle) {
+ ((DefaultSizeNodeFigure) figure).setDefaultSize(LayoutConstants.DEFAULT_COMBINED_FRAGMENT_WIDTH, LayoutConstants.DEFAULT_COMBINED_FRAGMENT_HEIGHT);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getCombinedFragment(getNotationView()).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/EndOfLifeEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/EndOfLifeEditPart.java
new file mode 100644
index 0000000000..5fbd92c09d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/EndOfLifeEditPart.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.editpolicies.ResizableEditPolicy;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramBorderNodeEditPartOperation;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNode2EditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ConnectionAnchorOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.EndOfLifeSelectionPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.LayoutEditPartConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+
+/**
+ * The edit part for lifeline end of lives. Implemented as a bordered node on
+ * the lifeline, and constrained on the south side of the lifeline. Such a node
+ * can be used either to represent the actual "End of Life" of the lifeline when
+ * it is explicitly destroyed or a "handle" which can be used to resize the
+ * lifeline vertically.
+ *
+ * @author pcdavid
+ */
+public class EndOfLifeEditPart extends DNode2EditPart {
+ /**
+ * Standard constructor, as expected by GMF.
+ *
+ * @param view
+ * the view.
+ */
+ public EndOfLifeEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPolicy getPrimaryDragEditPolicy() {
+ ResizableEditPolicy result = new EndOfLifeSelectionPolicy();
+ DDiagramElement dde = resolveDiagramElement();
+ if (dde instanceof DNode) {
+ DNode node = (DNode) dde;
+ DiagramBorderNodeEditPartOperation.updateResizeKind(result, node);
+ }
+ return result;
+ }
+
+ /**
+ * This method is overridden to have the EndOfLife (bordered node) starting
+ * from the border of the Instance Role.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void refresh() {
+ super.refresh();
+ SequenceEditPartsOperations.setBorderItemLocation(this, LayoutEditPartConstants.EOL_SIDE, LayoutEditPartConstants.EOL_BORDER_ITEM_OFFSET);
+ }
+
+ /**
+ * Overridden to register the diagram element.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * Overridden to unregister the diagram element.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getTargetConnectionAnchor(Request request) {
+ ConnectionAnchor anchor = super.getTargetConnectionAnchor(request);
+ if (anchor != null && new RequestQuery(request).isSequenceMessageCreation()) {
+ anchor = ConnectionAnchorOperation.safeCenterAnchor(anchor);
+ }
+ return anchor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getSourceConnectionAnchor(Request request) {
+ ConnectionAnchor anchor = super.getSourceConnectionAnchor(request);
+ if (anchor != null && new RequestQuery(request).isSequenceMessageCreation()) {
+ anchor = ConnectionAnchorOperation.safeCenterAnchor(anchor);
+ }
+ return anchor;
+ }
+
+ /***
+ * Get the lifeline edit part of the current end of life edit part.
+ *
+ * @return the lifeline edit part.
+ */
+ public LifelineEditPart getLifelineEditPart() {
+ EditPart parent = getParent();
+ if (parent instanceof LifelineEditPart) {
+ return (LifelineEditPart) parent;
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ExecutionEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ExecutionEditPart.java
new file mode 100644
index 0000000000..19da599c8b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ExecutionEditPart.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.editpolicies.ResizableEditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramBorderNodeEditPartOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.ExecutionSelectionEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.ExecutionItemLocator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.SequenceNodeFigure;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IStyleConfigurationRegistry;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.StyleConfiguration;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.AnchorProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.ICollapseMode;
+import org.eclipse.sirius.diagram.ui.tools.internal.util.EditPartQuery;
+
+/**
+ * Special edit part for Executions. Implemented as bordered nodes, either
+ * directly on a lifeline parts or on another execution.
+ *
+ * @author pcdavid, smonnier
+ */
+public class ExecutionEditPart extends AbstractSequenceBorderedEditPart {
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public ExecutionEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPolicy getPrimaryDragEditPolicy() {
+ final ResizableEditPolicy result = new ExecutionSelectionEditPolicy();
+ DDiagramElement dde = this.resolveDiagramElement();
+ if (dde instanceof DNode) {
+ DNode node = (DNode) dde;
+ DiagramBorderNodeEditPartOperation.updateResizeKind(result, node);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void handleNotificationEvent(Notification notification) {
+ super.handleNotificationEvent(notification);
+ if (notification.getEventType() == Notification.SET && notification.getNotifier() instanceof Bounds) {
+ final EditPart parentInstanceRole = new EditPartQuery(this).getFirstAncestorOfType(InstanceRoleEditPart.class);
+ if (parentInstanceRole != null) {
+ parentInstanceRole.refresh();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createNodePlate() {
+ DefaultSizeNodeFigure result = null;
+ final EObject eObj = resolveSemanticElement();
+ if (eObj instanceof DStylizable && eObj instanceof DDiagramElement) {
+ final DStylizable viewNode = (DStylizable) eObj;
+ final StyleConfiguration styleConfiguration = IStyleConfigurationRegistry.INSTANCE.getStyleConfiguration(((DDiagramElement) eObj).getDiagramElementMapping(), viewNode.getStyle());
+ final AnchorProvider anchorProvider = styleConfiguration.getAnchorProvider();
+ result = new SequenceNodeFigure(getMapMode().DPtoLP(5), getMapMode().DPtoLP(5), anchorProvider);
+ nodePlate = result;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IBorderItemLocator createBorderItemLocator(IFigure figure, DDiagramElement vpElementBorderItem) {
+ if (AbstractNodeEvent.viewpointElementPredicate().apply(vpElementBorderItem)) {
+ return new ExecutionItemLocator(this, figure);
+ } else {
+ return super.createBorderItemLocator(figure, vpElementBorderItem);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void refreshVisuals() {
+ super.refreshVisuals();
+ collapsedExecutionRefreshVisuals();
+ }
+
+ private void collapsedExecutionRefreshVisuals() {
+ DDiagramElement dde = resolveDiagramElement();
+ IBorderItemLocator bil = getBorderItemLocator();
+
+ if (dde == null || !(bil instanceof ExecutionItemLocator)) {
+ return;
+ }
+
+ // Modify locator constraint to collapse only the width.
+ if (new DDiagramElementQuery(dde).isIndirectlyCollapsed()) {
+ final int x = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getLocation_X())).intValue();
+ final int y = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getLocation_Y())).intValue();
+ final int width = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getSize_Width())).intValue();
+ final int height = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getSize_Height())).intValue();
+
+ bil.setConstraint(new Rectangle(x, y, width, height));
+
+ if (bil instanceof BorderItemLocator) {
+ ((BorderItemLocator) bil).setBorderItemOffset(ICollapseMode.COLLAPSE_DEFAULT_OFFSET);
+ }
+
+ if (getPrimaryFigure() != null) {
+ refreshFigure();
+ getPrimaryFigure().repaint();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getExecution(getNotationView()).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ISequenceEventEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ISequenceEventEditPart.java
new file mode 100644
index 0000000000..5dc151078a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ISequenceEventEditPart.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+
+/**
+ * Common interface for all the elements of a sequence diagram which represent
+ * an event associated to a (logical) time interval and thus a range of vertical
+ * coordinates. This includes lifelines (considered as a special case of
+ * executions), executions and messages.
+ *
+ * @author pcdavid, smonnier, mporhel
+ */
+public interface ISequenceEventEditPart extends IDiagramElementEditPart {
+ /**
+ * Returns the {@link ISequenceEvent} this {@link ISequenceEventEditPart}.
+ *
+ * @return the {@link ISequenceEvent} this {@link ISequenceEventEditPart}.
+ */
+ ISequenceEvent getISequenceEvent();
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InstanceRoleEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InstanceRoleEditPart.java
new file mode 100644
index 0000000000..4ff27b4b18
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InstanceRoleEditPart.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.Request;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.description.ExecutionMapping;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ConnectionAnchorOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.InstanceRoleResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.InstanceRoleSiriusGraphicalNodeEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.SouthCenteredBorderItemLocator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.LayoutEditPartConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+
+/**
+ * The edit part for lifeline instance roles.
+ *
+ * @author pcdavid, smonnier
+ */
+public class InstanceRoleEditPart extends DNodeEditPart {
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public InstanceRoleEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getTargetConnectionAnchor(Request request) {
+ ConnectionAnchor anchor = super.getTargetConnectionAnchor(request);
+ if (anchor != null && new RequestQuery(request).isSequenceMessageCreation()) {
+ anchor = ConnectionAnchorOperation.safeCenterAnchor(anchor);
+ }
+ return anchor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getSourceConnectionAnchor(Request request) {
+ ConnectionAnchor anchor = super.getSourceConnectionAnchor(request);
+ if (anchor != null && new RequestQuery(request).isSequenceMessageCreation()) {
+ anchor = ConnectionAnchorOperation.safeCenterAnchor(anchor);
+ }
+ return anchor;
+ }
+
+ /**
+ * This method has been overridden to use a specific BorderItemLocator to
+ * place the lifeline properly.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public IBorderItemLocator createBorderItemLocator(IFigure figure, DDiagramElement vpElementBorderItem) {
+ IBorderItemLocator result;
+ if (vpElementBorderItem.getMapping() instanceof ExecutionMapping) {
+ result = new SouthCenteredBorderItemLocator(figure, LayoutEditPartConstants.ROOT_EXECUTION_BORDER_ITEM_OFFSET);
+ } else {
+ result = super.createBorderItemLocator(figure, vpElementBorderItem);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on lifelines.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.PRIMARY_DRAG_ROLE.equals(key)) {
+ super.installEditPolicy(key, new InstanceRoleResizableEditPolicy());
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+ installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new InstanceRoleSiriusGraphicalNodeEditPolicy());
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ public InstanceRole getInstanceRole() {
+ return ISequenceElementAccessor.getInstanceRole(getNotationView()).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InteractionUseEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InteractionUseEditPart.java
new file mode 100644
index 0000000000..925a31a8e4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/InteractionUseEditPart.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker;
+import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.swt.SWT;
+
+import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException;
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.FlatContainerStyle;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager;
+import org.eclipse.sirius.description.ContainerMapping;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.description.FrameMapping;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.InteractionUseResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.SiriusWrapLabel;
+import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
+
+/**
+ * Special edit part for interaction uses.
+ *
+ * @author pcdavid, smonnier
+ *
+ */
+public class InteractionUseEditPart extends DNodeContainerEditPart implements ISequenceEventEditPart {
+ /**
+ * The centered label.
+ */
+ private SiriusWrapLabel fExpressionLabelFigure;
+
+ /**
+ * Post commit listener to refresh the centered label on targeted
+ * interaction change.
+ */
+ private NotificationListener usedInteractionLabelUpdater = new NotificationListener() {
+
+ public void notifyChanged(Notification notification) {
+ if (!notification.isTouch()) {
+ refreshUsedInteractionLabel();
+ }
+ }
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public InteractionUseEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on lifelines.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.PRIMARY_DRAG_ROLE.equals(key)) {
+ super.installEditPolicy(key, new InteractionUseResizableEditPolicy());
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * Computes the center label expression.
+ *
+ * @return the center label expression
+ */
+ protected String computeCenterLabelExpression() {
+ String centeredLabelText = "";
+ if (resolveSemanticElement() instanceof DNodeContainer) {
+ DNodeContainer dNodeContainer = (DNodeContainer) resolveSemanticElement();
+ ContainerMapping actualMapping = dNodeContainer.getActualMapping();
+ if (actualMapping instanceof FrameMapping) {
+ FrameMapping frameMapping = (FrameMapping) actualMapping;
+ String centerLabelExpression = frameMapping.getCenterLabelExpression();
+ EObject eObject = dNodeContainer.getTarget();
+ try {
+ centeredLabelText = evaluationExpression(eObject, centerLabelExpression);
+ } catch (EvaluationException e) {
+ RuntimeLoggerManager.INSTANCE.error(frameMapping, DescriptionPackage.eINSTANCE.getFrameMapping_CenterLabelExpression(), e);
+ }
+ }
+ }
+ return centeredLabelText;
+ }
+
+ private String evaluationExpression(EObject self, String expression) throws EvaluationException {
+ IInterpreter interpreter = null;
+ if (self != null) {
+ interpreter = InterpreterUtil.getInterpreter(self);
+ if (interpreter != null) {
+ return interpreter.evaluateString(self, expression);
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Refresh the centered label text.
+ */
+ private void refreshUsedInteractionLabel() {
+ if (fExpressionLabelFigure != null) {
+ fExpressionLabelFigure.setText(computeCenterLabelExpression());
+ // FIXME smonnier does not work on diagram opening
+ // ArrayList<AbstractDiagramNameEditPart> nameEditPartList =
+ // Lists.newArrayList(Iterables.filter(getChildren(),
+ // AbstractDiagramNameEditPart.class));
+ // if (nameEditPartList.size() == 1) {
+ // AbstractDiagramNameEditPart nameEditPart =
+ // nameEditPartList.get(0);
+ // if (nameEditPart.getFigure() instanceof WrapLabel) {
+ // WrapLabel titleBlock = (WrapLabel) nameEditPart.getFigure();
+ // fExpressionLabelFigure.setForegroundColor(titleBlock.getForegroundColor());
+ // fExpressionLabelFigure.setFont(titleBlock.getFont());
+ // }
+ // }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to add a post commit notification listener on all semantic
+ * elements for the centered label refresh.
+ */
+ @Override
+ public void activate() {
+ super.activate();
+
+ DiagramEventBroker broker = null;
+ final TransactionalEditingDomain theEditingDomain = getEditingDomain();
+ if (theEditingDomain != null) {
+ broker = DiagramEventBroker.getInstance(theEditingDomain);
+ }
+
+ if (broker != null) {
+ final Iterator<EObject> iterSemanticElements = resolveAllSemanticElements().iterator();
+ while (iterSemanticElements.hasNext()) {
+ final EObject semantic = iterSemanticElements.next();
+ broker.addNotificationListener(semantic, usedInteractionLabelUpdater);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to remove the post commit notification listener on all
+ * semantic elements for the centered label refresh.
+ */
+ @Override
+ public void deactivate() {
+ super.deactivate();
+
+ DiagramEventBroker broker = null;
+ final TransactionalEditingDomain theEditingDomain = getEditingDomain();
+ if (theEditingDomain != null) {
+ broker = DiagramEventBroker.getInstance(theEditingDomain);
+ }
+
+ if (broker != null) {
+ final Iterator<EObject> iterSemanticElements = resolveAllSemanticElements().iterator();
+ while (iterSemanticElements.hasNext()) {
+ final EObject semantic = iterSemanticElements.next();
+ broker.removeNotificationListener(semantic, usedInteractionLabelUpdater);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getInteractionUse(getNotationView()).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createMainFigure() {
+ NodeFigure figure = super.createMainFigure();
+
+ if (figure instanceof DefaultSizeNodeFigure) {
+ final EObject eObj = this.resolveSemanticElement();
+ if (eObj instanceof DDiagramElementContainer) {
+ final DDiagramElementContainer container = (DDiagramElementContainer) eObj;
+ if (container.getOwnedStyle() instanceof FlatContainerStyle) {
+ ((DefaultSizeNodeFigure) figure).setDefaultSize(LayoutConstants.DEFAULT_INTERACTION_USE_WIDTH, LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT);
+ }
+ }
+ }
+
+ // Add a centered label on the figure
+ fExpressionLabelFigure = new SiriusWrapLabel();
+ refreshUsedInteractionLabel();
+ fExpressionLabelFigure.setTextWrap(true);
+ fExpressionLabelFigure.setLabelAlignment(SWT.CENTER);
+ figure.add(fExpressionLabelFigure);
+
+ return figure;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LifelineEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LifelineEditPart.java
new file mode 100644
index 0000000000..65b7ef6099
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LifelineEditPart.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LineBorder;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.DragTracker;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPartViewer;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.requests.SelectionRequest;
+import org.eclipse.gmf.runtime.diagram.ui.tools.DragEditPartsTrackerEx;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.sirius.BorderedStyle;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.Style;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.description.EndOfLifeMapping;
+import org.eclipse.sirius.diagram.sequence.description.ExecutionMapping;
+import org.eclipse.sirius.diagram.sequence.description.StateMapping;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.ExecutionItemLocator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.LifelineNodeFigure;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.SouthCenteredBorderItemLocator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.LayoutEditPartConstants;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IStyleConfigurationRegistry;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.StyleConfiguration;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.AnchorProvider;
+import org.eclipse.sirius.ui.tools.api.color.VisualBindingManager;
+
+/**
+ * Special edit part for Executions. They are treated as bordered nodes.
+ *
+ * @author pcdavid, smonnier
+ */
+public class LifelineEditPart extends AbstractSequenceBorderedEditPart {
+ private static final boolean ENABLE_LIFELINE_SELECTION = false;
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public LifelineEditPart(final View view) {
+ super(view);
+ }
+
+ /**
+ * This method is overridden to have the Lifeline (bordered node) starting
+ * from the border of the Instance Role.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void refreshVisuals() {
+ updateLifelineWidthAndColor();
+
+ super.refreshVisuals();
+ SequenceEditPartsOperations.setBorderItemLocation(this, PositionConstants.SOUTH, LayoutEditPartConstants.ROOT_EXECUTION_BORDER_ITEM_OFFSET);
+ }
+
+ private void updateLifelineWidthAndColor() {
+ DDiagramElement dde = this.resolveDiagramElement();
+ Style style = dde.getStyle();
+ if (style instanceof BorderedStyle) {
+ BorderedStyle borderedStyle = (BorderedStyle) style;
+ int borderSize = borderedStyle.getBorderSize().intValue();
+ Color fg = VisualBindingManager.getDefault().getColorFromRGBValues(borderedStyle.getBorderColor());
+
+ // Update LifelineNodeFigure
+ nodePlate.setLineWidth(borderSize);
+ if (fg != null) {
+ nodePlate.setForegroundColor(fg);
+ }
+
+ // Update its border.
+ if (nodePlate.getBorder() instanceof LineBorder) {
+ LineBorder lineBorder = (LineBorder) nodePlate.getBorder();
+ lineBorder.setWidth(borderSize);
+ if (fg != null) {
+ lineBorder.setColor(fg);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method has been overridden to be able to select the parent
+ * InstanceRoleEditPart when selecting this LifelineEditPart.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSelected(int value) {
+ if (ENABLE_LIFELINE_SELECTION) {
+ super.setSelected(value);
+ } else {
+ getParent().setSelected(value);
+ }
+ }
+
+ /**
+ * This method has been overridden to use a specific Tracker to be able to
+ * select the InstanceRole and group requests.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public DragTracker getDragTracker(Request request) {
+ if (!ENABLE_LIFELINE_SELECTION) {
+ if (request instanceof SelectionRequest) {
+ return new LifeLineSelectionDragEditPartsTrackerEx(this);
+ }
+ }
+ return super.getDragTracker(request);
+ }
+
+ /**
+ * This method has been overridden to use a specific BorderItemLocator to
+ * place the Destroy end item properly.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public IBorderItemLocator createBorderItemLocator(IFigure figure, DDiagramElement vpElementBorderItem) {
+ IBorderItemLocator result;
+ if (vpElementBorderItem.getMapping() instanceof EndOfLifeMapping) {
+ result = new SouthCenteredBorderItemLocator(figure, LayoutEditPartConstants.EOL_BORDER_ITEM_OFFSET);
+ } else if (vpElementBorderItem.getMapping() instanceof ExecutionMapping || vpElementBorderItem.getMapping() instanceof StateMapping) {
+ result = new ExecutionItemLocator(this, figure);
+ } else {
+ result = super.createBorderItemLocator(figure, vpElementBorderItem);
+ }
+ return result;
+ }
+
+ /**
+ * This method is overridden to use a specific figure for this border node.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createNodePlate() {
+ DefaultSizeNodeFigure result = null;
+ final EObject eObj = resolveSemanticElement();
+ if (eObj instanceof DStylizable && eObj instanceof DDiagramElement) {
+ final DStylizable viewNode = (DStylizable) eObj;
+ final StyleConfiguration styleConfiguration = IStyleConfigurationRegistry.INSTANCE.getStyleConfiguration(((DDiagramElement) eObj).getDiagramElementMapping(), viewNode.getStyle());
+ final AnchorProvider anchorProvider = styleConfiguration.getAnchorProvider();
+ result = new LifelineNodeFigure(getMapMode().DPtoLP(5), getMapMode().DPtoLP(5), anchorProvider);
+ nodePlate = result;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getLifeline(getNotationView()).get();
+ }
+
+ /**
+ * Specific tracker used to select the parent InstanceRole instead of the
+ * RootExecution and append request on RootExecution to InstanceRole.
+ *
+ * @author smonnier
+ */
+ private final class LifeLineSelectionDragEditPartsTrackerEx extends DragEditPartsTrackerEx {
+
+ /**
+ * Constructor.
+ *
+ * @param sourceEditPart
+ * the execution edit part
+ */
+ public LifeLineSelectionDragEditPartsTrackerEx(EditPart sourceEditPart) {
+ super(sourceEditPart);
+ }
+
+ /**
+ * This method has been overridden to be able to manipulate the parent
+ * InstanceRoleEditPart as well as this LifelineEditPart. For instance,
+ * moving the LifelineEditPart will also move the parent
+ * InstanceRoleEditPart.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected List createOperationSet() {
+ List createOperationSet = super.createOperationSet();
+ if (createOperationSet.contains(LifelineEditPart.this)) {
+ if (getParent() instanceof InstanceRoleEditPart) {
+ createOperationSet.add(getParent());
+ }
+ }
+ return createOperationSet;
+ }
+
+ /**
+ * This method has been overridden to be able to select the parent
+ * InstanceRoleEditPart when selecting this LifelineEditPart.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected void performSelection() {
+ if (hasSelectionOccurred()) {
+ return;
+ }
+ setFlag(FLAG_SELECTION_PERFORMED, true);
+ EditPartViewer viewer = getCurrentViewer();
+ List<?> selectedObjects = viewer.getSelectedEditParts();
+
+ if (getCurrentInput().isModKeyDown(SWT.MOD1)) {
+ if (selectedObjects.contains(getSourceEditPart().getParent())) {
+ viewer.deselect(getSourceEditPart());
+ } else {
+ viewer.appendSelection(getSourceEditPart().getParent());
+ }
+ } else if (getCurrentInput().isShiftKeyDown()) {
+ viewer.appendSelection(getSourceEditPart().getParent());
+ } else {
+ viewer.select(getSourceEditPart().getParent());
+ }
+ }
+
+ /**
+ * Always disable the clone with Ctrl key in Sirius because it only
+ * clone the graphical element and not the semantic element.
+ *
+ * @param cloneActive
+ * true if cloning should be active (never considered here)
+ *
+ * @see org.eclipse.gef.tools.DragEditPartsTracker#setCloneActive(boolean)
+ */
+ @Override
+ protected void setCloneActive(boolean cloneActive) {
+ super.setCloneActive(false);
+ }
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LostMessageEndEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LostMessageEndEditPart.java
new file mode 100644
index 0000000000..25d9770c64
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/LostMessageEndEditPart.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.editpolicies.ResizableEditPolicy;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramNodeEditPartOperation;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ConnectionAnchorOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.LostMessageEndSelectionPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+
+/**
+ * The edit part for lost message end.
+ *
+ * @author mporhel
+ */
+public class LostMessageEndEditPart extends DNodeEditPart {
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public LostMessageEndEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * Use the same y location as the corresponding source connection anchor,
+ * stored in ViewLocationHint, to improve user feedback.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getSourceConnectionAnchor(Request request) {
+ return ConnectionAnchorOperation.safeCenterAnchor(super.getSourceConnectionAnchor(request));
+ }
+
+ /**
+ * Use the same y location as the corresponding source connection anchor,
+ * stored in ViewLocationHint, to improve user feedback.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getTargetConnectionAnchor(Request request) {
+ return ConnectionAnchorOperation.safeCenterAnchor(super.getTargetConnectionAnchor(request));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPolicy getPrimaryDragEditPolicy() {
+ ResizableEditPolicy result = new LostMessageEndSelectionPolicy();
+ DDiagramElement dde = resolveDiagramElement();
+ if (dde instanceof DNode) {
+ DNode node = (DNode) dde;
+ DiagramNodeEditPartOperation.updateResizeKind(result, node);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on lost message ends.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.PRIMARY_DRAG_ROLE.equals(key)) {
+ super.installEditPolicy(key, getPrimaryDragEditPolicy());
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ public LostMessageEnd getLostMessageEnd() {
+ return ISequenceElementAccessor.getLostMessageEnd(getNotationView()).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ObservationPointEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ObservationPointEditPart.java
new file mode 100644
index 0000000000..638ff29889
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/ObservationPointEditPart.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.editpolicies.ResizableEditPolicy;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.CollapseFilter;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramBorderNodeEditPartOperation;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramNodeEditPartOperation;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ObservationPoint;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ConnectionAnchorOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.ObservationPointSelectionPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IStyleConfigurationRegistry;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.StyleConfiguration;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.AirDefaultSizeNodeFigure;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.AnchorProvider;
+
+/**
+ * The edit part for {@link ObservationPoint}s.
+ *
+ * @author mporhel
+ */
+public class ObservationPointEditPart extends DNodeEditPart {
+
+ private DefaultSizeNodeFigure nodePlate;
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public ObservationPointEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * Use the same y location as the corresponding source connection anchor,
+ * stored in ViewLocationHint, to improve user feedback.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getSourceConnectionAnchor(Request request) {
+ return ConnectionAnchorOperation.safeCenterAnchor(super.getSourceConnectionAnchor(request));
+ }
+
+ /**
+ * Use the same y location as the corresponding source connection anchor,
+ * stored in ViewLocationHint, to improve user feedback.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getTargetConnectionAnchor(Request request) {
+ return ConnectionAnchorOperation.safeCenterAnchor(super.getTargetConnectionAnchor(request));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPolicy getPrimaryDragEditPolicy() {
+ ResizableEditPolicy result = new ObservationPointSelectionPolicy();
+ DDiagramElement dde = resolveDiagramElement();
+ if (dde instanceof DNode) {
+ DNode node = (DNode) dde;
+ DiagramNodeEditPartOperation.updateResizeKind(result, node);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on lost message ends.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.PRIMARY_DRAG_ROLE.equals(key)) {
+ super.installEditPolicy(key, getPrimaryDragEditPolicy());
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ public ObservationPoint getObservationPoint() {
+ return ISequenceElementAccessor.getObservationPoint(getNotationView()).get();
+ }
+
+ @Override
+ protected void handleNotificationEvent(Notification notification) {
+ super.handleNotificationEvent(notification);
+
+ if (SiriusPackage.eINSTANCE.getDDiagramElement_GraphicalFilters().equals(notification.getFeature())) {
+ boolean collapse = notification.getNewValue() instanceof CollapseFilter && notification.getOldValue() == null;
+ boolean uncollapse = notification.getOldValue() instanceof CollapseFilter && notification.getNewValue() == null;
+ if (collapse || uncollapse) {
+ DDiagramElement dde = resolveDiagramElement();
+ if (dde instanceof DNode) {
+ DNode node = (DNode) dde;
+
+ EditPolicy ep = getEditPolicy(EditPolicy.PRIMARY_DRAG_ROLE);
+ if (ep instanceof ResizableEditPolicy) {
+ DiagramBorderNodeEditPartOperation.updateResizeKind((ResizableEditPolicy) ep, node);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void refreshVisuals() {
+ super.refreshVisuals();
+
+ DDiagramElement node = resolveDiagramElement();
+ if (new DDiagramElementQuery(node).isCollapsed()) {
+ final int x = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getLocation_X())).intValue();
+ final int y = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getLocation_Y())).intValue();
+ final int width = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getSize_Width())).intValue();
+ final int height = ((Integer) getStructuralFeatureValue(NotationPackage.eINSTANCE.getSize_Height())).intValue();
+
+ Rectangle collpasedSize = new Rectangle(x, y, width, height);
+ ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), collpasedSize);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramBorderNodeEditPart#activate()
+ */
+ @Override
+ public void activate() {
+ if (nodePlate instanceof AirDefaultSizeNodeFigure)
+ ((AirDefaultSizeNodeFigure) nodePlate).setZoomManager(getZoomManager());
+ super.activate();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramBorderNodeEditPart#deactivate()
+ */
+ @Override
+ public void deactivate() {
+ super.deactivate();
+ if (nodePlate instanceof AirDefaultSizeNodeFigure)
+ ((AirDefaultSizeNodeFigure) nodePlate).setZoomManager(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IFigure getNodePlate() {
+ return nodePlate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createNodePlate() {
+ DefaultSizeNodeFigure result = new ObservationPointFigure(10, 10, null);
+ final EObject eObj = resolveSemanticElement();
+ if (eObj instanceof DStylizable && eObj instanceof DDiagramElement) {
+ final DStylizable viewNode = (DStylizable) eObj;
+ final StyleConfiguration styleConfiguration = IStyleConfigurationRegistry.INSTANCE.getStyleConfiguration(((DDiagramElement) eObj).getDiagramElementMapping(), viewNode.getStyle());
+ final AnchorProvider anchorProvider = styleConfiguration.getAnchorProvider();
+ result = new ObservationPointFigure(getMapMode().DPtoLP(5), getMapMode().DPtoLP(5), anchorProvider);
+ nodePlate = result;
+ }
+ return result;
+ }
+
+ /**
+ * ObservationPoint is a top level node but collapsing should be possible.
+ *
+ * @author mporhel
+ */
+ private class ObservationPointFigure extends AirDefaultSizeNodeFigure {
+ /**
+ * Create a new {@link AirDefaultSizeNodeFigure}.
+ *
+ * @param defSize
+ * the size.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public ObservationPointFigure(final Dimension defSize, final AnchorProvider anchorProvider) {
+ super(defSize, anchorProvider);
+ }
+
+ /**
+ * Create a new {@link AirDefaultSizeNodeFigure}.
+ *
+ * @param width
+ * the width.
+ * @param height
+ * the height.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public ObservationPointFigure(final int width, final int height, final AnchorProvider anchorProvider) {
+ super(width, height, anchorProvider);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Dimension getMinimumSize(int hint, int hint2) {
+ return new Dimension(0, 0);
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandCompartmentEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandCompartmentEditPart.java
new file mode 100644
index 0000000000..d745c58b5e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandCompartmentEditPart.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.graphical.edit.policies.NodeCreationEditPolicy;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerViewNodeContainerCompartment2EditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ExecutionOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceNodeCreationPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+
+/**
+ * Custom edit part to customize what happens inside an operand.
+ *
+ * @author pcdavid
+ */
+public class OperandCompartmentEditPart extends DNodeContainerViewNodeContainerCompartment2EditPart {
+ /**
+ * The visual ID. Same as a normal container compartment.
+ *
+ * @see DNodeContainerViewNodeContainerCompartment2EditPart.VISUAL_ID
+ */
+ public static final int VISUAL_ID = 7002;
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view <code>controlled</code> by this editpart.
+ */
+ public OperandCompartmentEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+ ExecutionOperations.replaceEditPolicy(this, EditPolicy.CONTAINER_ROLE, new SequenceNodeCreationPolicy(), NodeCreationEditPolicy.class);
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandEditPart.java
new file mode 100644
index 0000000000..8131cd4f89
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/OperandEditPart.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.FlatContainerStyle;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramContainerEditPartOperation;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainer2EditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.OperandResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.OperandFigure;
+
+/**
+ * Special edit part for operands inside combined fragments.
+ *
+ * @author pcdavid
+ */
+public class OperandEditPart extends DNodeContainer2EditPart implements ISequenceEventEditPart {
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public OperandEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveDiagramElement());
+ }
+
+ /**
+ * Overridden to install a specific edit policy managing the moving and
+ * resizing requests on operands.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.PRIMARY_DRAG_ROLE.equals(key)) {
+ super.installEditPolicy(key, new OperandResizableEditPolicy());
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addDropShadow(NodeFigure figure, IFigure shape) {
+ // Removes the shadow border to have operands border overlapping
+ // combined fragment border
+ figure.setBorder(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createNodePlate() {
+ NodeFigure nodePlate = super.createNodePlate();
+
+ final EObject eObj = this.resolveSemanticElement();
+ if (nodePlate instanceof DefaultSizeNodeFigure && eObj instanceof DDiagramElementContainer) {
+ final DDiagramElementContainer container = (DDiagramElementContainer) eObj;
+ if (container.getOwnedStyle() instanceof FlatContainerStyle) {
+ ((DefaultSizeNodeFigure) nodePlate).setDefaultSize(LayoutConstants.DEFAULT_OPERAND_WIDTH, LayoutConstants.DEFAULT_OPERAND_HEIGHT);
+ }
+ }
+
+ return nodePlate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected NodeFigure createMainFigure() {
+ NodeFigure figure = super.createMainFigure();
+
+ return figure;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to create our own figure without border but only a bottom dash
+ * line.
+ */
+ @Override
+ protected IFigure createNodeShape() {
+ // We recover the combined fragment to have the operand separator with
+ // the same style as the combined fragment border
+ Operand operand = ISequenceElementAccessor.getOperand(getNotationView()).get();
+ final EObject eObj = operand.getCombinedFragment().getNotationNode().getElement();
+ if (eObj instanceof DStylizable && eObj instanceof DDiagramElement) {
+ return new OperandFigure(DiagramContainerEditPartOperation.getCornerDimension(this), DiagramContainerEditPartOperation.getBackgroundStyle(this), operand);
+ } else {
+ return super.createNodeShape();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getOperand(getNotationView()).get();
+ }
+
+ /**
+ * Overridden.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void refreshVisuals() {
+ if (getParent() != null) {
+ super.refreshVisuals();
+ }
+ }
+
+ /**
+ * Finds the parent {@link CombinedFragmentEditPart}.
+ *
+ * @return the parent {@link CombinedFragmentEditPart}
+ */
+ public CombinedFragmentEditPart getParentCombinedFragmentEditPart() {
+ Preconditions.checkArgument(getParent() instanceof CombinedFragmentCompartmentEditPart);
+ Preconditions.checkArgument(getParent().getParent() instanceof CombinedFragmentEditPart);
+ return (CombinedFragmentEditPart) getParent().getParent();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceBracketEdgeEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceBracketEdgeEditPart.java
new file mode 100644
index 0000000000..3182f568e2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceBracketEdgeEditPart.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.business.internal.bracket.BracketRelativeBendpoint;
+import org.eclipse.sirius.diagram.business.internal.bracket.Direction;
+import org.eclipse.sirius.diagram.graphical.edit.part.specific.BracketEdgeEditPart;
+
+/**
+ * A custom bracket edit part to force default bracket direction.
+ *
+ * @author mporhel
+ */
+public class SequenceBracketEdgeEditPart extends BracketEdgeEditPart {
+
+ /**
+ * Default constructor.
+ *
+ * @param view
+ * the underlying {@link View}.
+ */
+ public SequenceBracketEdgeEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * Get default draw2d bendpoints.
+ *
+ * @return default draw2d bendpoints
+ */
+ @Override
+ protected List<BracketRelativeBendpoint> getDefaultFigureConstraint() {
+ final List<BracketRelativeBendpoint> defaultFigureConstraint = Lists.newArrayList();
+ defaultFigureConstraint.add(new BracketRelativeBendpoint(getConnectionFigure(), Direction.LEFT.ordinal(), Direction.LEFT.ordinal(), 50));
+ return defaultFigureConstraint;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceDiagramEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceDiagramEditPart.java
new file mode 100644
index 0000000000..74a97a4b6f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceDiagramEditPart.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.transaction.ResourceSetListener;
+import org.eclipse.emf.transaction.ResourceSetListenerImpl;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.business.api.dialect.DialectManager;
+import org.eclipse.sirius.business.api.session.ModelChangeTrigger;
+import org.eclipse.sirius.business.api.session.SessionEventBroker;
+import org.eclipse.sirius.diagram.graphical.edit.policies.ContainerCreationEditPolicy;
+import org.eclipse.sirius.diagram.internal.edit.parts.DDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.refresh.RefreshLayoutCommand;
+import org.eclipse.sirius.diagram.sequence.business.internal.refresh.RefreshLayoutScope;
+import org.eclipse.sirius.diagram.sequence.business.internal.refresh.RefreshLayoutTrigger;
+import org.eclipse.sirius.diagram.sequence.business.internal.refresh.SequenceCanonicalSynchronizerAdapter;
+import org.eclipse.sirius.diagram.sequence.business.internal.refresh.SequenceCanonicalSynchronizerAdapterScope;
+import org.eclipse.sirius.diagram.sequence.ui.business.internal.refresh.VisibilityEventHandler;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command.SequenceEMFCommandFactory;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ExecutionOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceContainerCreationPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceZOrderingRefresher;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.tools.api.properties.PropertiesService;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+import org.eclipse.sirius.tools.api.ui.property.IPropertiesProvider;
+
+/**
+ * The edit part for sequence diagrams themselves.
+ *
+ * @author pcdavid
+ */
+public class SequenceDiagramEditPart extends DDiagramEditPart {
+ /**
+ * The listener in charge with refreshing the graphical ordering and layout
+ * when the model and/or graphics positions change.
+ */
+ private final VisibilityEventHandler semanticOrderingSynchronizer;
+
+ private IDiagramCommandFactoryProvider previousProvider;
+
+ private ModelChangeTrigger refreshLayout;
+
+ private ModelChangeTrigger sequenceCanonicalSynchronizer;
+
+ private ResourceSetListener refreshZorder = new ResourceSetListenerImpl() {
+ @Override
+ public boolean isPostcommitOnly() {
+ return true;
+ }
+
+ @Override
+ public void resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent event) {
+ new SequenceZOrderingRefresher(SequenceDiagramEditPart.this).run();
+ refreshConnectionsBendpoints();
+ }
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param diagramView
+ * the view.
+ */
+ public SequenceDiagramEditPart(final View diagramView) {
+ super(diagramView);
+ this.semanticOrderingSynchronizer = new VisibilityEventHandler();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+ ExecutionOperations.replaceEditPolicy(this, EditPolicy.CONTAINER_ROLE, new SequenceContainerCreationPolicy(), ContainerCreationEditPolicy.class);
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveSemanticElement());
+ super.addNotify();
+ Object property = getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (property instanceof DDiagramEditor) {
+ DDiagramEditor diagramEditor = (DDiagramEditor) property;
+ setCustomCommandFactoryProvider(diagramEditor);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveSemanticElement());
+ Object property = getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (property instanceof DDiagramEditor && this.previousProvider != null) {
+ DDiagramEditor diagramEditor = (DDiagramEditor) property;
+ diagramEditor.setEmfCommandFactoryProvider(this.previousProvider);
+ this.previousProvider = null;
+ }
+ }
+
+ /**
+ * Overridden to do some initialization and add a post-commit listener.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void activate() {
+ super.activate();
+ /*
+ * Once the diagram (and all its children) is active, refresh the
+ * various ordering. This is especially needed when creating/opening a
+ * diagram as some commands need a properly initialized graphically
+ * ordering to work.
+ */
+ boolean autoRefresh = PropertiesService.getInstance().getPropertiesProvider().getProperty(IPropertiesProvider.KEY_AUTO_REFRESH);
+ boolean refreshOnOpen = DialectManager.INSTANCE.isRefreshActivatedOnRepresentationOpening();
+ getEditingDomain().getCommandStack().execute(new RefreshLayoutCommand(getEditingDomain(), getDiagramView(), autoRefresh || refreshOnOpen));
+ getEditingDomain().addResourceSetListener(semanticOrderingSynchronizer);
+ getEditingDomain().addResourceSetListener(refreshZorder);
+
+ Option<SessionEventBroker> broker = getSessionBroker();
+ if (broker.some()) {
+ SessionEventBroker sessionEventBroker = broker.get();
+
+ Predicate<Notification> refreshLayoutScope = new RefreshLayoutScope();
+ refreshLayout = new RefreshLayoutTrigger(getDiagramView());
+ sessionEventBroker.addLocalTrigger(refreshLayoutScope, refreshLayout);
+
+ Predicate<Notification> sequenceCanonicalSynchronizerLayoutScope = new SequenceCanonicalSynchronizerAdapterScope();
+ sequenceCanonicalSynchronizer = new SequenceCanonicalSynchronizerAdapter();
+ sessionEventBroker.addLocalTrigger(sequenceCanonicalSynchronizerLayoutScope, sequenceCanonicalSynchronizer);
+ }
+ }
+
+ private Option<SessionEventBroker> getSessionBroker() {
+ DDiagramEditor diagramEditor = (DDiagramEditor) this.getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (diagramEditor != null) {
+ return Options.newSome(diagramEditor.getSession().getEventBroker());
+ }
+ return Options.newNone();
+ }
+
+ private void setCustomCommandFactoryProvider(DDiagramEditor diagramEditor) {
+ previousProvider = diagramEditor.getEmfCommandFactoryProvider();
+ diagramEditor.setEmfCommandFactoryProvider(new IDiagramCommandFactoryProvider() {
+
+ /** the EMF command factory */
+ private IDiagramCommandFactory commandFactory;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider#getCommandFactory(org.eclipse.emf.transaction.TransactionalEditingDomain)
+ */
+ public IDiagramCommandFactory getCommandFactory(final TransactionalEditingDomain editingDomain) {
+ if (commandFactory == null) {
+ commandFactory = new SequenceEMFCommandFactory(SequenceDiagramEditPart.this);
+ }
+ return commandFactory;
+ }
+ });
+ }
+
+ /**
+ * Overridden to remove the post-commit listener and other initializations.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void deactivate() {
+ getEditingDomain().removeResourceSetListener(refreshZorder);
+ getEditingDomain().removeResourceSetListener(semanticOrderingSynchronizer);
+ Option<SessionEventBroker> broker = getSessionBroker();
+ if (broker.some()) {
+ SessionEventBroker sessionEventBroker = broker.get();
+ sessionEventBroker.removeLocalTrigger(refreshLayout);
+ sessionEventBroker.removeLocalTrigger(sequenceCanonicalSynchronizer);
+ }
+ super.deactivate();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to be accessible from {@link SequenceZOrderingRefresher}.
+ */
+ @Override
+ public void reorderChild(EditPart child, int index) {
+ super.reorderChild(child, index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void refreshChildren() {
+ super.refreshChildren();
+ refreshConnectionsBendpoints();
+ new SequenceZOrderingRefresher(this).run();
+ }
+
+ /**
+ * Refresh the bendpoints of source & target connections.
+ */
+ protected void refreshConnectionsBendpoints() {
+ for (SequenceMessageEditPart connectionEditPart : Iterables.filter(getConnections(), SequenceMessageEditPart.class)) {
+ connectionEditPart.refreshBendpoints();
+ }
+ }
+
+ /**
+ * Returns the underlying sequence diagram element.
+ *
+ * @return the underlying sequence diagram element.
+ */
+ public SequenceDiagram getSequenceDiagram() {
+ return ISequenceElementAccessor.getSequenceDiagram(getDiagramView()).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageEditPart.java
new file mode 100644
index 0000000000..27c483c323
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageEditPart.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.ConnectionRouter;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.gef.DragTracker;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.requests.ReconnectRequest;
+import org.eclipse.gef.requests.SelectionRequest;
+import org.eclipse.gmf.runtime.diagram.ui.figures.LabelLocator;
+import org.eclipse.gmf.runtime.diagram.ui.util.EditPartUtil;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import org.eclipse.sirius.diagram.internal.edit.parts.DEdgeEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceLaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceMessageEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.tools.SequenceMessageSelectConnectionEditPartTracker;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.SequenceMessageLabelLocator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceMessagesRouter;
+
+/**
+ * The edit part for sequence diagrams messages.
+ *
+ * @author pcdavid, smonnier
+ */
+public class SequenceMessageEditPart extends DEdgeEditPart implements ISequenceEventEditPart {
+ /**
+ * id for extended meta data.
+ */
+ public static final String MSG_TO_SELF_TOP_MOVE = "messageToSelfTopMove";
+
+ /**
+ * The global router for all the messages.
+ */
+ private static final ConnectionRouter ROUTER = new SequenceMessagesRouter();
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public SequenceMessageEditPart(final View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ SequenceEditPartsOperations.registerDiagramElement(this, resolveDiagramElement());
+ super.addNotify();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ SequenceEditPartsOperations.unregisterDiagramElement(this, resolveSemanticElement());
+ }
+
+ /**
+ * Force our own router for sequence messages.
+ */
+ @SuppressWarnings("restriction")
+ @Override
+ protected void installRouter() {
+ getPrimaryShape().setConnectionRouter(ROUTER);
+ setCursor(org.eclipse.gmf.runtime.gef.ui.internal.l10n.Cursors.CURSOR_SEG_MOVE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createDefaultEditPolicies() {
+ super.createDefaultEditPolicies();
+
+ // Handle $endBefore for launch tools.
+ installEditPolicy(org.eclipse.sirius.diagram.tools.api.requests.RequestConstants.REQ_LAUNCH_TOOL, new SequenceLaunchToolEditPolicy());
+ }
+
+ /**
+ * Override to install the MessageEditPolicy.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("restriction")
+ public void installEditPolicy(Object key, EditPolicy editPolicy) {
+ if (EditPolicy.CONNECTION_BENDPOINTS_ROLE.equals(key)) {
+ super.installEditPolicy(key, new SequenceMessageEditPolicy());
+ setCursor(org.eclipse.gmf.runtime.gef.ui.internal.l10n.Cursors.CURSOR_SEG_MOVE);
+ } else {
+ super.installEditPolicy(key, editPolicy);
+ }
+ }
+
+ /**
+ * Overridden to hide feedback on reconnect attempts, which are not allowed.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void showSourceFeedback(Request request) {
+ if (!(request instanceof ReconnectRequest)) {
+ super.showSourceFeedback(request);
+ }
+ }
+
+ /**
+ * Overridden to hide feedback on reconnect attempts, which are not allowed.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void showTargetFeedback(Request request) {
+ if (!(request instanceof ReconnectRequest)) {
+ super.showTargetFeedback(request);
+ }
+ }
+
+ /**
+ * Sets the mouse cursor when the mouse is over this edit part.
+ *
+ * @param cursor
+ * the cursor shape.
+ */
+ public void setCursor(final org.eclipse.swt.graphics.Cursor cursor) {
+ EditPartUtil.synchronizeRunnableToMainThread(this, new Runnable() {
+ public void run() {
+ Connection connectionFigure = SequenceMessageEditPart.this.getConnectionFigure();
+ connectionFigure.setCursor(cursor);
+ };
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPart getTargetEditPart(Request request) {
+ if (request instanceof SelectionRequest) {
+ this.setCursor(org.eclipse.gmf.runtime.gef.ui.internal.l10n.Cursors.CURSOR_SEG_MOVE);
+ }
+ return super.getTargetEditPart(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void refreshBendpoints() {
+ RelativeBendpoints bendpoints = (RelativeBendpoints) getEdge().getBendpoints();
+ List<?> modelConstraint = bendpoints.getPoints();
+ List<org.eclipse.draw2d.RelativeBendpoint> figureConstraint = new ArrayList<org.eclipse.draw2d.RelativeBendpoint>();
+ for (int i = 0; i < modelConstraint.size(); i++) {
+ RelativeBendpoint wbp = (RelativeBendpoint) modelConstraint.get(i);
+ org.eclipse.draw2d.RelativeBendpoint rbp = new org.eclipse.draw2d.RelativeBendpoint(getConnectionFigure());
+ rbp.setRelativeDimensions(new Dimension(wbp.getSourceX(), wbp.getSourceY()), new Dimension(wbp.getTargetX(), wbp.getTargetY()));
+ rbp.setWeight(0);
+ figureConstraint.add(rbp);
+ }
+ getConnectionFigure().setRoutingConstraint(figureConstraint);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setLayoutConstraint(EditPart child, IFigure childFigure, Object constraint) {
+ if (constraint instanceof LabelLocator) {
+ // custom locator to avoid vertical label position change during
+ // horizontal move of lifelines.
+ SequenceMessageLabelLocator smll = new SequenceMessageLabelLocator(childFigure.getParent(), (LabelLocator) constraint);
+ super.setLayoutConstraint(child, childFigure, smll);
+ } else {
+ super.setLayoutConstraint(child, childFigure, constraint);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DragTracker getDragTracker(Request req) {
+ return new SequenceMessageSelectConnectionEditPartTracker(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getMessage(getNotationView()).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageNameEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageNameEditPart.java
new file mode 100644
index 0000000000..d35a4155d0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/SequenceMessageNameEditPart.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramEdgeEditPart.ViewEdgeFigure;
+import org.eclipse.sirius.diagram.internal.edit.parts.DEdgeNameEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.InverseRelativeNodePositionOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.SequenceMessageLabelLocator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * The edit part for sequence message labels.
+ *
+ * @author mporhel, smonnier
+ */
+public class SequenceMessageNameEditPart extends DEdgeNameEditPart {
+ /**
+ * The visual ID.
+ */
+ public static final int VISUAL_ID = DEdgeNameEditPart.VISUAL_ID;
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public SequenceMessageNameEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void refresh() {
+ if (resolveSemanticElement() instanceof DEdge) {
+ super.refresh();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command getCommand(Request request) {
+ Command result = super.getCommand(request);
+ if (result != null && result.canExecute() && new RequestQuery(request).isMove() && messageIsRightToLeft()) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(getEditingDomain(), result.getLabel());
+ ctc.compose(new CommandProxy(result));
+ ICommand fixPositionCommand = CommandFactory.createICommand(getEditingDomain(), new InverseRelativeNodePositionOperation((Node) getNotationView()));
+ ctc.compose(fixPositionCommand);
+ result = new ICommandProxy(ctc);
+ }
+ return result;
+ }
+
+ private boolean messageIsRightToLeft() {
+ IFigure figure = getFigure();
+ ViewEdgeFigure parentFigure = null;
+ if (figure != null && figure.getParent() instanceof ViewEdgeFigure) {
+ parentFigure = (ViewEdgeFigure) figure.getParent();
+ }
+ return SequenceMessageLabelLocator.isRightToLeft(parentFigure);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/StateEditPart.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/StateEditPart.java
new file mode 100644
index 0000000000..c7874c29f3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/part/StateEditPart.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.editpolicies.ResizableEditPolicy;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.diagram.edit.internal.part.AbstractDiagramNodeEditPartOperation;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramBorderNodeEditPartOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.StateSelectionEditPolicy;
+
+/**
+ * Special edit part for States. Implemented as bordered nodes, either directly
+ * on a lifeline or on an execution.
+ *
+ * @author smonnier
+ */
+public class StateEditPart extends ExecutionEditPart {
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the view.
+ */
+ public StateEditPart(View view) {
+ super(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISequenceEvent getISequenceEvent() {
+ return ISequenceElementAccessor.getState(getNotationView()).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.edit.api.part.IAbstractDiagramNodeEditPart#createBorderItemLocator(org.eclipse.draw2d.IFigure,
+ * org.eclipse.sirius.DDiagramElement)
+ */
+ @Override
+ public IBorderItemLocator createBorderItemLocator(final IFigure figure, final DDiagramElement vpElementBorderItem) {
+ return AbstractDiagramNodeEditPartOperation.createBorderItemLocator(this, figure, vpElementBorderItem);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPolicy getPrimaryDragEditPolicy() {
+ final ResizableEditPolicy result = new StateSelectionEditPolicy();
+ DDiagramElement dde = this.resolveDiagramElement();
+ if (dde instanceof DNode) {
+ DNode node = (DNode) dde;
+ DiagramBorderNodeEditPartOperation.updateResizeKind(result, node);
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java
new file mode 100644
index 0000000000..17ba0c814d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/AbstractFrameResizableEditPolicy.java
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.FreeformViewport;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.AlignmentRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.swt.graphics.Color;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.graphical.edit.policies.AirResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractFrame;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractInteractionFrameValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.ISEComplexMoveValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.HorizontalGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.RangeGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * A specific AirResizableEditPolicy to manage interaction use roles move &
+ * resize requests.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractFrameResizableEditPolicy extends AirResizableEditPolicy {
+
+ /**
+ * The color to use for the horizontal feedback rules shown when
+ * moving/resizing an execution.
+ */
+ private static final Color FRAME_FEEDBACK_COLOR = ColorConstants.lightGray;
+
+ private Collection<Figure> guides = Lists.newArrayList();
+
+ /**
+ * Constructor.
+ */
+ public AbstractFrameResizableEditPolicy() {
+ super();
+ setResizeDirections(PositionConstants.NORTH_SOUTH);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getResizeDirections() {
+ return super.getResizeDirections();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setResizeDirections(int newDirections) {
+ super.setResizeDirections(PositionConstants.NORTH_SOUTH);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+ eraseChangeBoundsFeedback(request);
+ cancelHorizontalDelta(request);
+
+ super.showChangeBoundsFeedback(request);
+
+ ISequenceEventEditPart hostPart = (ISequenceEventEditPart) getHost();
+ RequestQuery requestQuery = new RequestQuery(request);
+
+ ISequenceEvent frame = hostPart.getISequenceEvent();
+ if (hostPart.getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isMove()) {
+ ISEComplexMoveValidator validator = ISEComplexMoveValidator.getOrCreateValidator(request, requestQuery, frame);
+ if (validator != null) {
+ SequenceInteractionFeedBackBuilder feedBackBuilder = new SequenceInteractionFeedBackBuilder(validator, getFeedbackLayer(), hostPart);
+ for (Figure fig : feedBackBuilder.buildFeedBack()) {
+ addFeedback(fig);
+ guides.add(fig);
+ }
+ }
+ } else if (requestQuery.isResize()) {
+ Rectangle newBounds = getNewBounds(getHostAbsoluteBounds().getCopy(), request);
+ Figure frameGuide = new RangeGuide(FRAME_FEEDBACK_COLOR, new Range(newBounds.y, newBounds.y + Math.max(0, newBounds.height)), false);
+ Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+ bounds.y = newBounds.y;
+ bounds.height = newBounds.height;
+ frameGuide.setBounds(bounds);
+ addFeedback(frameGuide);
+ guides.add(frameGuide);
+
+ // display a guide for each Operand start
+ for (ISequenceEventEditPart child : getChildrenToFeedBack(request)) {
+ newBounds = getNewBounds(getAbsoluteBounds(child.getFigure()), request);
+ HorizontalGuide childGuide = createAndAddFeedbackHGuide(newBounds.getTop().y);
+ guides.add(childGuide);
+ }
+
+ if (frame instanceof AbstractFrame) {
+ AbstractInteractionFrameValidator validator = AbstractInteractionFrameValidator.getOrCreateResizeValidator(request, (AbstractFrame) frame);
+ if (!validator.isValid()) {
+ feedBackConflicts(validator);
+ }
+
+ feedBackExpansion(validator);
+ }
+ }
+ }
+
+ private void feedBackExpansion(AbstractInteractionFrameValidator validator) {
+ Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+ Range expansionZone = validator.getExpansionZone();
+ if (!expansionZone.isEmpty()) {
+ Rectangle screenRange = new Rectangle(0, expansionZone.getLowerBound(), 0, expansionZone.width());
+ screenRange.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+ Range expand = Range.verticalRange(screenRange);
+
+ RangeGuide expansion = new RangeGuide(validator.isValid() ? ColorConstants.blue : ColorConstants.red, expand, true);
+ bounds.height = expand.width();
+ bounds.y = expand.getLowerBound();
+ expansion.setBounds(bounds);
+ addFeedback(expansion);
+ guides.add(expansion);
+ }
+ }
+
+ private void feedBackConflicts(AbstractInteractionFrameValidator validator) {
+ for (Integer conflict : validator.getInvalidPositions()) {
+ Point conflictingPosition = new Point(0, conflict);
+ conflictingPosition.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+
+ Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+ bounds.y = conflictingPosition.y;
+ bounds.height = 1;
+
+ HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+ conflictGuide.setBounds(bounds);
+ addFeedback(conflictGuide);
+ guides.add(conflictGuide);
+ }
+ }
+
+ private Rectangle getNewBounds(Rectangle oldBounds, ChangeBoundsRequest cbr) {
+ Rectangle newBounds = cbr.getTransformedRectangle(oldBounds).getCopy();
+
+ FreeformViewport viewport = FigureUtilities.getFreeformViewport(getHostFigure());
+ if (viewport != null) {
+ newBounds.translate(viewport.getViewLocation());
+ }
+
+ return newBounds;
+ }
+
+ private HorizontalGuide createAndAddFeedbackHGuide(int y) {
+ Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+ bounds.height = 1;
+ bounds.y = y;
+
+ HorizontalGuide guide = new HorizontalGuide(FRAME_FEEDBACK_COLOR, y);
+ guide.setBounds(bounds);
+ addFeedback(guide);
+ return guide;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void eraseChangeBoundsFeedback(ChangeBoundsRequest request) {
+ // cancelHorizontalDelta((ChangeBoundsRequest) request);
+ removeFeedBackOnGuides();
+ super.eraseChangeBoundsFeedback(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAutoSizeCommand(Request request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAlignCommand(AlignmentRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * Cancel horizontal changes of the given request.
+ *
+ * @param request
+ * a request.
+ */
+ protected void cancelHorizontalDelta(ChangeBoundsRequest request) {
+ if (request == null) {
+ return;
+ }
+
+ Point moveDelta = request.getMoveDelta();
+ if (moveDelta != null) {
+ request.setMoveDelta(new Point(0, moveDelta.y));
+ }
+
+ Dimension sizeDelta = request.getSizeDelta();
+ if (sizeDelta != null) {
+ request.setSizeDelta(new Dimension(0, sizeDelta.height));
+ }
+ }
+
+ private void removeFeedBackOnGuides() {
+ if (guides != null && !guides.isEmpty()) {
+ for (Figure hGuide : guides) {
+ removeFeedback(hGuide);
+ }
+ guides.clear();
+ }
+ }
+
+ /**
+ * Return absolute bounds of the current host.
+ *
+ * @return absolute bounds of the current host.
+ */
+ private Rectangle getHostAbsoluteBounds() {
+ return getAbsoluteBounds(getHostFigure());
+ }
+
+ private Rectangle getAbsoluteBounds(IFigure figure) {
+ Rectangle bounds = figure.getBounds().getCopy();
+ figure.getParent().translateToAbsolute(bounds);
+ return bounds;
+ }
+
+ /**
+ * Additional feedback.
+ *
+ * @param request
+ * the request to feedback.
+ * @return a collection of {@link ISequenceEventEditPart} to feedback.
+ */
+ protected abstract Collection<ISequenceEventEditPart> getChildrenToFeedBack(ChangeBoundsRequest request);
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/CombinedFragmentResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/CombinedFragmentResizableEditPolicy.java
new file mode 100644
index 0000000000..c82a0691e5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/CombinedFragmentResizableEditPolicy.java
@@ -0,0 +1,415 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.draw2d.PositionConstants;
+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.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.IdentityCommand;
+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.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.Size;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.VerticalSpaceExpansion;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentCompartmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.OperandEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractInteractionFrameValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.ISEComplexMoveValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * A specific AirResizableEditPolicy to combined fragment roles move & resize
+ * requests.
+ *
+ * @author smonnier
+ */
+public class CombinedFragmentResizableEditPolicy extends AbstractFrameResizableEditPolicy {
+
+ private static final String RESIZE = "Resize";
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ cancelHorizontalDelta(request);
+ CombinedFragmentEditPart hostPart = (CombinedFragmentEditPart) getHost();
+
+ ICommand solution = IdentityCommand.INSTANCE;
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (hostPart.getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isMove()) {
+ ISEComplexMoveValidator validator = ISEComplexMoveValidator.getOrCreateValidator(request, requestQuery, hostPart.getISequenceEvent());
+ if (validator != null && validator.isValid()) {
+ CompositeTransactionalCommand ctc = buildNewMoveCommand(hostPart, request, validator);
+ postProcessDefaultCommand(hostPart, request, ctc, null);
+ solution = ctc;
+ } else {
+ solution = org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE;
+ }
+ }
+ return new ICommandProxy(solution);
+ }
+
+ private CompositeTransactionalCommand buildNewMoveCommand(CombinedFragmentEditPart hostPart, ChangeBoundsRequest request, ISEComplexMoveValidator validator) {
+ TransactionalEditingDomain editingDomain = hostPart.getEditingDomain();
+ ISEComplexMoveCommandBuilder builder = new ISEComplexMoveCommandBuilder(editingDomain, "Execution Move Composite Command", new RequestQuery(request), validator);
+ return builder.buildCommand();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getResizeCommand(ChangeBoundsRequest request) {
+ cancelHorizontalDelta(request);
+
+ CombinedFragmentEditPart cfep = (CombinedFragmentEditPart) getHost();
+ ISequenceEvent fragment = cfep.getISequenceEvent();
+ AbstractInteractionFrameValidator validator = AbstractInteractionFrameValidator.getOrCreateResizeValidator(request, (CombinedFragment) fragment);
+
+ Command result;
+ if (validator != null && validator.isValid()) {
+ CompositeTransactionalCommand ctc = getRezizeCustomCommand(cfep, request);
+
+ Range expansionZone = validator == null ? Range.emptyRange() : validator.getExpansionZone();
+ ICommand autoExpand = null;
+ if (expansionZone != null && !expansionZone.isEmpty()) {
+ SequenceDiagram diagram = fragment.getDiagram();
+ Collection<ISequenceEvent> eventToIgnore = Collections.singletonList(fragment);
+ autoExpand = CommandFactory.createICommand(cfep.getEditingDomain(), new VerticalSpaceExpansion(diagram, expansionZone, 0, eventToIgnore));
+ }
+
+ postProcessDefaultCommand(cfep, request, ctc, autoExpand);
+ result = new ICommandProxy(ctc);
+ } else {
+ result = UnexecutableCommand.INSTANCE;
+ }
+
+ return result;
+ }
+
+ private CompositeTransactionalCommand getRezizeCustomCommand(CombinedFragmentEditPart self, ChangeBoundsRequest request) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(self.getEditingDomain(), "Combined Fragment Resize Composite Command");
+ ctc.add(CombinedFragmentResizableEditPolicy.getResizeBorderItemTCommand(self, request));
+ Option<CombinedFragment> combinedFragmentOption = ISequenceElementAccessor.getCombinedFragment(self.getNotationView());
+ if (combinedFragmentOption.some() && !combinedFragmentOption.get().getOperands().isEmpty()) {
+ // if (!validateResize(request, combinedFragmentOption.get())) {
+ // // FIXME this validation should be removed because done in the
+ // // validator now.
+ // return UnexecutableCommand.INSTANCE;
+ // }
+ if (request.getResizeDirection() == PositionConstants.NORTH) {
+ // we need to process the same resize to the first operand
+ // and keep the others unchanged
+ addResizeOperandsFromNorthCommand(ctc, request);
+ } else if (request.getResizeDirection() == PositionConstants.SOUTH) {
+ // we need to process the same resize to the last operand
+ // and keep the others unchanged
+ addResizeOperandsFromSouthCommand(ctc, request);
+ }
+ }
+ return ctc;
+ }
+
+ private void postProcessDefaultCommand(CombinedFragmentEditPart self, ChangeBoundsRequest request, CompositeTransactionalCommand ctc, ICommand autoExpand) {
+ if (ctc != null && ctc.canExecute()) {
+ if (autoExpand != null) {
+ ctc.compose(autoExpand);
+ }
+
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, self.getISequenceEvent());
+ }
+ }
+
+ /**
+ * Returns the command to resize the combined fragment from the north face,
+ * and therefore resize up the first operand.
+ *
+ * @param ctc
+ * the current transactional command.
+ * @param request
+ * the request for a resize.
+ */
+ private void addResizeOperandsFromNorthCommand(CompositeTransactionalCommand ctc, ChangeBoundsRequest request) {
+ // we need to process the same resize to the first operand
+ OperandEditPart firstOperandEditPart = getFirstOperandEditPart();
+ Option<Operand> firstOperand = ISequenceElementAccessor.getOperand(firstOperandEditPart.getNotationView());
+ int position = 0;
+
+ OperandEditPart followingOperandEditPart = getFollowingOperandEditPart(position);
+ Option<Operand> followingOperand = followingOperandEditPart != null ? ISequenceElementAccessor.getOperand(followingOperandEditPart.getNotationView()) : Options.<Operand> newNone();
+
+ position++;
+
+ Point newLocation = null;
+ Dimension newDimension = null;
+ if (firstOperand.some()) {
+ Range verticalRange = firstOperand.get().getVerticalRange();
+ newLocation = new Point(0, LayoutConstants.COMBINED_FRAGMENT_TITLE_HEIGHT);
+ newDimension = new Dimension(firstOperand.get().getBounds().width, verticalRange.width() + request.getSizeDelta().height);
+ ctc.add(createOperandSetBoundsCommand(firstOperandEditPart, newLocation, newDimension));
+ }
+
+ if (followingOperandEditPart != null && followingOperand.some()) {
+
+ // recurse
+ while (followingOperandEditPart != null && followingOperand.some()) {
+ Range verticalRange = followingOperand.get().getVerticalRange();
+ newLocation = new Point(0, newLocation.y + newDimension.height);
+ newDimension = new Dimension(followingOperand.get().getBounds().width, verticalRange.width());
+ ctc.add(createOperandSetBoundsCommand(followingOperandEditPart, newLocation, newDimension));
+ followingOperandEditPart = getFollowingOperandEditPart(position);
+ followingOperand = followingOperandEditPart != null ? ISequenceElementAccessor.getOperand(followingOperandEditPart.getNotationView()) : Options.<Operand> newNone();
+ position++;
+ }
+
+ }
+ }
+
+ /**
+ * Returns the command to resize the combined fragment from the south face,
+ * and therefore resize down the last operand.
+ *
+ * @param ctc
+ * the current transactional command.
+ * @param request
+ * the request for a resize.
+ */
+ public void addResizeOperandsFromSouthCommand(CompositeTransactionalCommand ctc, ChangeBoundsRequest request) {
+ // we need to process the same resize to the first operand if it is
+ // single
+ OperandEditPart firstOperandEditPart = getFirstOperandEditPart();
+ Option<Operand> firstOperand = ISequenceElementAccessor.getOperand(firstOperandEditPart.getNotationView());
+ int position = 0;
+
+ OperandEditPart followingOperandEditPart = getFollowingOperandEditPart(position);
+ Option<Operand> followingOperand = followingOperandEditPart != null ? ISequenceElementAccessor.getOperand(followingOperandEditPart.getNotationView()) : Options.<Operand> newNone();
+
+ position++;
+
+ OperandEditPart lastOperandEditPart = getLastOperandEditPart();
+
+ Point newLocation = null;
+ Dimension newDimension = null;
+ if (firstOperand.some()) {
+ Range verticalRange = firstOperand.get().getVerticalRange();
+ newLocation = new Point(0, LayoutConstants.COMBINED_FRAGMENT_TITLE_HEIGHT);
+ if (firstOperandEditPart == lastOperandEditPart) {
+ newDimension = new Dimension(firstOperand.get().getBounds().width, verticalRange.width() + request.getSizeDelta().height);
+ } else {
+ newDimension = new Dimension(firstOperand.get().getBounds().width, verticalRange.width());
+ }
+ ctc.add(createOperandSetBoundsCommand(firstOperandEditPart, newLocation, newDimension));
+ }
+
+ if (followingOperandEditPart != null && followingOperand.some()) {
+ Range verticalRange = followingOperand.get().getVerticalRange();
+
+ // recurse
+ while (followingOperandEditPart != null && followingOperand.some() && followingOperandEditPart != lastOperandEditPart) {
+ newLocation = new Point(0, newLocation.y + newDimension.height);
+ newDimension = new Dimension(followingOperand.get().getBounds().width, verticalRange.width());
+ ctc.add(createOperandSetBoundsCommand(followingOperandEditPart, newLocation, newDimension));
+ followingOperandEditPart = getFollowingOperandEditPart(position);
+ followingOperand = followingOperandEditPart != null ? ISequenceElementAccessor.getOperand(followingOperandEditPart.getNotationView()) : Options.<Operand> newNone();
+ verticalRange = followingOperand.get().getVerticalRange();
+ position++;
+ }
+ newLocation = new Point(0, newLocation.y + newDimension.height);
+ newDimension = new Dimension(followingOperand.get().getBounds().width, verticalRange.width() + request.getSizeDelta().height);
+ ctc.add(createOperandSetBoundsCommand(lastOperandEditPart, newLocation, newDimension));
+
+ }
+ }
+
+ /**
+ * Finds the following {@link OperandEditPart} of the current
+ * {@link OperandEditPart} identified by the index currentOperandIndex.
+ *
+ * @param currentOperandIndex
+ * the index of the current {@link OperandEditPart}
+ * @return the following {@link OperandEditPart}
+ */
+ private OperandEditPart getFollowingOperandEditPart(int currentOperandIndex) {
+ CombinedFragmentCompartmentEditPart combinedFragmentCompartmentEditPart = Iterables.getOnlyElement(Iterables.filter(getHost().getChildren(), CombinedFragmentCompartmentEditPart.class));
+ Iterable<OperandEditPart> operandEditPartList = Iterables.filter(combinedFragmentCompartmentEditPart.getChildren(), OperandEditPart.class);
+ for (OperandEditPart operandEditPart : operandEditPartList) {
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(operandEditPart.getNotationView());
+ if (operandOption.some()) {
+ Operand operand = operandOption.get();
+ int operandIndex = operand.getIndex();
+ if (operandIndex == currentOperandIndex + 1) {
+ return operandEditPart;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds the first {@link OperandEditPart}.
+ *
+ * @return the first {@link OperandEditPart}
+ */
+ private OperandEditPart getFirstOperandEditPart() {
+ CombinedFragmentCompartmentEditPart combinedFragmentCompartmentEditPart = Iterables.getOnlyElement(Iterables.filter(getHost().getChildren(), CombinedFragmentCompartmentEditPart.class));
+ for (OperandEditPart operandEditPart : Iterables.filter(combinedFragmentCompartmentEditPart.getChildren(), OperandEditPart.class)) {
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(operandEditPart.getNotationView());
+ if (operandOption.some()) {
+ Operand operand = operandOption.get();
+ int operandIndex = operand.getIndex();
+ if (operandIndex == 0) {
+ return operandEditPart;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds the last {@link OperandEditPart}.
+ *
+ * @return the last {@link OperandEditPart}
+ */
+ private OperandEditPart getLastOperandEditPart() {
+ CombinedFragmentCompartmentEditPart combinedFragmentCompartmentEditPart = Iterables.getOnlyElement(Iterables.filter(getHost().getChildren(), CombinedFragmentCompartmentEditPart.class));
+ Iterable<OperandEditPart> operandEditPartList = Iterables.filter(combinedFragmentCompartmentEditPart.getChildren(), OperandEditPart.class);
+ int childrenOperandEditPartNumber = Iterables.size(operandEditPartList);
+ for (OperandEditPart operandEditPart : operandEditPartList) {
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(operandEditPart.getNotationView());
+ if (operandOption.some()) {
+ Operand operand = operandOption.get();
+ int operandIndex = operand.getIndex();
+ if (operandIndex == childrenOperandEditPartNumber - 1) {
+ return operandEditPart;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the command to resize a bordered node.
+ *
+ * @param part
+ * the edit part corresponding to the bordered node.
+ * @param request
+ * the request for a resize.
+ * @return the command to resize a bordered node.
+ */
+ public static AbstractTransactionalCommand getResizeBorderItemTCommand(IGraphicalEditPart part, ChangeBoundsRequest request) {
+ final EObject semantic = part.resolveSemanticElement();
+ if (semantic instanceof DNodeContainer) {
+ final double zoom = ((ZoomManager) part.getViewer().getProperty(ZoomManager.class.toString())).getZoom();
+ final Dimension dimension = CombinedFragmentResizableEditPolicy.getDimensionFromView(part);
+ final Point position = CombinedFragmentResizableEditPolicy.getPositionFromView(part);
+ dimension.height += request.getSizeDelta().height / zoom;
+ switch (request.getResizeDirection()) {
+ case PositionConstants.NORTH:
+ case PositionConstants.NORTH_WEST:
+ case PositionConstants.NORTH_EAST:
+ position.y -= request.getSizeDelta().height / zoom;
+ break;
+ default:
+ break;
+ }
+ return new SetBoundsCommand(part.getEditingDomain(), RESIZE, new EObjectAdapter(part.getNotationView()), new Rectangle(position, dimension));
+ }
+ return null;
+ }
+
+ /**
+ * Creates the {@link SetBoundsCommand} to resize an operand.
+ *
+ * @param part
+ * the {@link OperandEditPart}
+ * @param location
+ * the new location of the operand
+ * @param dimension
+ * the new dimension of the operand
+ * @return a command to resize an operand
+ */
+ private AbstractTransactionalCommand createOperandSetBoundsCommand(IGraphicalEditPart part, Point location, Dimension dimension) {
+ return new SetBoundsCommand(part.getEditingDomain(), RESIZE, new EObjectAdapter(part.getNotationView()), new Rectangle(location, dimension));
+ }
+
+ private static Point getPositionFromView(IGraphicalEditPart part) {
+ final Point position = new Point();
+ if (part.getNotationView() instanceof Node && ((Node) part.getNotationView()).getLayoutConstraint() instanceof Location) {
+ final Location location = (Location) ((Node) part.getNotationView()).getLayoutConstraint();
+ position.x = location.getX();
+ position.y = location.getY();
+ }
+ return position;
+ }
+
+ private static Dimension getDimensionFromView(IGraphicalEditPart part) {
+ final Dimension dimension = new Dimension();
+ if (part.getNotationView() instanceof Node && ((Node) part.getNotationView()).getLayoutConstraint() instanceof Size) {
+ final Size size = (Size) ((Node) part.getNotationView()).getLayoutConstraint();
+ dimension.width = size.getWidth();
+ dimension.height = size.getHeight();
+ }
+ return dimension;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceEventEditPart> getChildrenToFeedBack(ChangeBoundsRequest request) {
+ Collection<ISequenceEventEditPart> feedback = Lists.newArrayList();
+ if (getHost() instanceof CombinedFragmentEditPart && new RequestQuery(request).isMove()) {
+ CombinedFragmentEditPart cfep = (CombinedFragmentEditPart) getHost();
+ for (CombinedFragmentCompartmentEditPart cpt : Iterables.filter(cfep.getChildren(), CombinedFragmentCompartmentEditPart.class)) {
+ Iterables.addAll(feedback, Iterables.filter(cpt.getChildren(), OperandEditPart.class));
+ }
+ }
+ return feedback;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/EndOfLifeSelectionPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/EndOfLifeSelectionPolicy.java
new file mode 100644
index 0000000000..a5852aae72
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/EndOfLifeSelectionPolicy.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+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.UnexecutableCommand;
+import org.eclipse.gef.requests.AlignmentRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.diagram.business.internal.query.DNodeQuery;
+import org.eclipse.sirius.diagram.graphical.edit.policies.SpecificBorderItemSelectionEditPolicy;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.EndOfLifeOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ShiftDescendantMessagesOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.EndOfLifeEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.SequenceDiagramEPQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * This policy controls the moves of {@link EndOfLifeEditPart}s, and in
+ * particular how such moves actually resize the parent lifeline.
+ *
+ * @author pcdavid
+ */
+public class EndOfLifeSelectionPolicy extends SpecificBorderItemSelectionEditPolicy {
+ /**
+ * Overridden to validate the host type.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void setHost(EditPart host) {
+ Preconditions.checkArgument(host instanceof EndOfLifeEditPart);
+ super.setHost(host);
+ }
+
+ /**
+ * Convenience method to return the host part with the correct type.
+ *
+ * @return returns the host of this policy, with the appropriate type.
+ */
+ protected EndOfLifeEditPart getEOL() {
+ return (EndOfLifeEditPart) getHost();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAlignCommand(AlignmentRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ Command result = UnexecutableCommand.INSTANCE;
+ constrainMoveVertically(request);
+ if (canResizeLifeline(getEOL(), request)) {
+ ChangeBoundsRequest cbr = EndOfLifeOperations.getLifelineResizeRequest(request, getEOL(), getEOL());
+ if (cbr != null) {
+ result = getLifelineMovesCommand(getEOL(), cbr);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void showSourceFeedback(Request request) {
+ constrainMoveVertically(request);
+ super.showSourceFeedback(request);
+ if (request instanceof ChangeBoundsRequest && canResizeLifeline(getEOL(), (ChangeBoundsRequest) request)) {
+ EndOfLifeOperations.showEndOfLifeFeedback(request, getEOL(), getEOL());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void eraseSourceFeedback(Request request) {
+ constrainMoveVertically(request);
+ super.eraseSourceFeedback(request);
+ EndOfLifeOperations.eraseEndOfLifeFeedback((LifelineEditPart) getEOL().getParent(), request);
+ }
+
+ /**
+ * Modifies the requested moves so that the part only moves vertically.
+ * Horizontal motion is disabled/ignored.
+ */
+ private void constrainMoveVertically(Request request) {
+ if (request instanceof ChangeBoundsRequest) {
+ ChangeBoundsRequest cbr = (ChangeBoundsRequest) request;
+ cbr.setMoveDelta(new Point(0, cbr.getMoveDelta().y));
+ }
+ }
+
+ private Command getLifelineMovesCommand(EndOfLifeEditPart self, ChangeBoundsRequest cbr) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(self.getEditingDomain(), "Lifelines moves command from end of life");
+ Option<EndOfLife> endOfLife = ISequenceElementAccessor.getEndOfLife(self.getNotationView());
+ LifelineEditPart lep = self.getLifelineEditPart();
+ boolean destroyed = endOfLife.some() && endOfLife.get().isExplicitelyDestroyed();
+
+ if (lep != null) {
+ if (destroyed) {
+ /*
+ * Moving a real EOL (i.e. one which represents the explicit
+ * destruction of the message) only resizes the corresponding
+ * lifeline.
+ */
+ addLifelineResizeCommand(self, cbr, ctc, lep);
+ } else {
+ /*
+ * Otherwise the EOL is just a handle to control the vertical
+ * range of the whole scenario, so we resize all the lifelines
+ * which are free, i.e. not explicitly destroyed at some
+ * specific position.
+ */
+ SequenceDiagramEditPart diagram = EditPartsHelper.getSequenceDiagramPart(self);
+ for (LifelineEditPart lifeline : new SequenceDiagramEPQuery(diagram).getAllLifelines()) {
+ if (!((Lifeline) lifeline.getISequenceEvent()).isExplicitlyDestroyed()) {
+ addLifelineResizeCommand(self, cbr, ctc, lifeline);
+ }
+ }
+ }
+ }
+ ICommandProxy iCommandProxy = new ICommandProxy(ctc);
+ iCommandProxy.setLabel(ctc.getLabel());
+ return iCommandProxy;
+ }
+
+ private void addLifelineResizeCommand(EndOfLifeEditPart self, ChangeBoundsRequest cbr, CompositeTransactionalCommand ctc, LifelineEditPart lep) {
+ cbr.setEditParts(lep);
+ ctc.compose(new CommandProxy(lep.getCommand(cbr)));
+
+ Dimension sizeDelta = cbr.getSizeDelta().getCopy();
+ GraphicalHelper.screen2logical(sizeDelta, getEOL());
+ TransactionalEditingDomain domain = getEOL().getEditingDomain();
+ ctc.compose(CommandFactory.createICommand(domain, new ShiftDescendantMessagesOperation(lep.getISequenceEvent(), sizeDelta.height, true, false, false)));
+ }
+
+ private boolean canResizeLifeline(EndOfLifeEditPart self, ChangeBoundsRequest request) {
+ Option<EndOfLife> endOfLife = ISequenceElementAccessor.getEndOfLife(self.getNotationView());
+ boolean destroyed = endOfLife.some() && endOfLife.get().isExplicitelyDestroyed();
+ boolean result = !destroyed || request.isConstrainedMove();
+ LifelineEditPart lep = self.getLifelineEditPart();
+ if (result && lep != null && (org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants.REQ_DROP.equals(request.getType()) || RequestConstants.REQ_MOVE.equals(request.getType()))) {
+ Range range = lep.getISequenceEvent().getVerticalRange();
+ int moveDeltaY = request.getMoveDelta().y;
+ int rangeLimit = getRangeLimit(self, lep, range, moveDeltaY, destroyed);
+ result = range.getUpperBound() + moveDeltaY >= rangeLimit;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+
+ private int getRangeLimit(EndOfLifeEditPart self, LifelineEditPart lep, Range range, int moveDeltaY, boolean isDestroyed) {
+ SequenceDiagramEditPart sdep = EditPartsHelper.getSequenceDiagramPart(self);
+ int rangeLimit = range.getLowerBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+
+ if (!isDestroyed) {
+ View lifelineView = (View) lep.getModel();
+ Lifeline lifeline = ISequenceElementAccessor.getLifeline(lifelineView).get();
+ DNode dNode = (DNode) lifelineView.getElement();
+
+ rangeLimit = Math.max(rangeLimit, new DNodeQuery(dNode).getDefaultDimension().height + lifeline.getVerticalRange().getLowerBound());
+ EventEnd lastEnd = SequenceGraphicalHelper.getEndBefore((SequenceDDiagram) sdep.resolveSemanticElement(), range.getUpperBound());
+ if (moveDeltaY < 0 && lastEnd != null) {
+ SingleEventEnd see;
+ if (lastEnd instanceof SingleEventEnd) {
+ see = (SingleEventEnd) lastEnd;
+ } else {
+ see = ((CompoundEventEnd) lastEnd).getEventEnds().iterator().next();
+ }
+
+ ISequenceEventEditPart ise = EditPartsHelper.findISequenceEvent(see, sdep);
+ rangeLimit = Math.max(rangeLimit, SequenceEditPartsOperations.getVerticalRange(ise).getUpperBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+ }
+ } else {
+ rangeLimit = Math.max(lep.getISequenceEvent().getOccupiedRange().getUpperBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN, rangeLimit);
+ }
+ return rangeLimit;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java
new file mode 100644
index 0000000000..3ad4f7037b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSelectionEditPolicy.java
@@ -0,0 +1,696 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.FreeformViewport;
+import org.eclipse.draw2d.IFigure;
+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.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPartViewer;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.IdentityCommand;
+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.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.swt.graphics.Color;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramBorderNodeEditPartOperation;
+import org.eclipse.sirius.diagram.graphical.edit.policies.SpecificBorderItemSelectionEditPolicy;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetMessageRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetVerticalRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.ShiftDirectSubExecutionsOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.VerticalSpaceExpansion;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ShiftDescendantMessagesOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractNodeEventResizeSelectionValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.ISEComplexMoveValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.HorizontalGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.RangeGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * Specialization of the default policy for executions, in order to validate and
+ * execute the specific resize and move behaviors needed for sequence diagrams.
+ *
+ * @author pcdavid
+ */
+public class ExecutionSelectionEditPolicy extends SpecificBorderItemSelectionEditPolicy {
+
+ /**
+ * The color to use for the horizontal feedback rules shown when
+ * moving/resizing an execution.
+ */
+ protected static final Color EXECUTION_FEEDBACK_COLOR = ColorConstants.lightGray;
+
+ /**
+ * Additional figures for feedback.
+ */
+ protected Collection<Figure> guides = Lists.newArrayList();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ cancelHorizontalDelta(request);
+ ICommand solution = IdentityCommand.INSTANCE;
+ ExecutionEditPart hostPart = (ExecutionEditPart) getHost();
+
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (hostPart.getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isMove()) {
+ ISEComplexMoveValidator validator = ISEComplexMoveValidator.getOrCreateValidator(request, requestQuery, hostPart.getISequenceEvent());
+ if (validator != null && validator.isValid()) {
+ solution = buildMoveCommand(hostPart, request, validator);
+ } else {
+ solution = org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE;
+ }
+ }
+ return new ICommandProxy(solution);
+ }
+
+ private ICommand buildMoveCommand(ExecutionEditPart hostPart, ChangeBoundsRequest request, ISEComplexMoveValidator validator) {
+ TransactionalEditingDomain editingDomain = hostPart.getEditingDomain();
+ RequestQuery requestQuery = new RequestQuery(request);
+ ISEComplexMoveCommandBuilder builder = new ISEComplexMoveCommandBuilder(editingDomain, "Execution Move Composite Command", requestQuery, validator);
+ return postProcessCommand(builder.buildCommand(), hostPart, requestQuery);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getResizeCommand(ChangeBoundsRequest request) {
+ Command result = UnexecutableCommand.INSTANCE;
+ ExecutionEditPart hostPart = (ExecutionEditPart) getHost();
+ AbstractNodeEvent host = (AbstractNodeEvent) hostPart.getISequenceEvent();
+
+ AbstractNodeEventResizeSelectionValidator validator = AbstractNodeEventResizeSelectionValidator.getOrCreateValidator(request, host);
+
+ if (validator.isValid()) {
+ ICommand solution = buildResizeCommand(request, hostPart, validator);
+ if (solution == null) {
+ solution = IdentityCommand.INSTANCE;
+ }
+ result = new ICommandProxy(solution);
+ }
+ return result;
+ }
+
+ private ICommand buildResizeCommand(ChangeBoundsRequest request, ExecutionEditPart hostPart, AbstractNodeEventResizeSelectionValidator validator) {
+ TransactionalEditingDomain editingDomain = hostPart.getEditingDomain();
+ ICommand solution = null;
+
+ AbstractNodeEvent self = (AbstractNodeEvent) hostPart.getISequenceEvent();
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (requestQuery.isMultiSelectionOperation()) {
+ validator.setExpansionZone(null);
+ }
+
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(hostPart.getEditingDomain(), "Execution Resize Composite Command");
+ if (needVerticalSpaceExpansion(validator, request)) {
+ SequenceDiagramEditPart diagram = EditPartsHelper.getSequenceDiagramPart(hostPart);
+ Collection<ISequenceEvent> eventToIgnore = Collections.singletonList((ISequenceEvent) self);
+ ctc.compose(CommandFactory.createICommand(editingDomain, new VerticalSpaceExpansion(diagram.getSequenceDiagram(), validator.getExpansionZone(), 0, eventToIgnore))); // FinalParentHelper.computeLinkedSiblings(requestQuery))));
+ }
+ if (validator.getFinalHierarchicalParent().equals(self.getHierarchicalParentEvent())) {
+ Command cmd = DiagramBorderNodeEditPartOperation.getResizeBorderItemCommand((ExecutionEditPart) getHost(), request, false);
+ ctc.add(new CommandProxy(cmd));
+ ctc.setLabel(cmd.getLabel());
+
+ if (self instanceof Execution) {
+ addChildrenAdjustmentCommands((Execution) self, ctc, editingDomain, request, validator);
+ }
+ solution = postProcessCommand(ctc, hostPart, requestQuery);
+ }
+ return solution;
+ }
+
+ /**
+ * Add refresh ordering commands and reorder commands.
+ *
+ * @param ctc
+ * the current composite command to complete.
+ * @param selfEditPart
+ * the current edit part
+ * @param requestQuery
+ * query on the request
+ * @return the completed command
+ */
+ protected ICommand postProcessCommand(CompositeTransactionalCommand ctc, ExecutionEditPart selfEditPart, RequestQuery requestQuery) {
+ AbstractNodeEvent self = (AbstractNodeEvent) selfEditPart.getISequenceEvent();
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, selfEditPart);
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(ctc, selfEditPart);
+
+ List<Message> linkedMessages = self.getLinkedMessages();
+ if (!linkedMessages.isEmpty() && !linkedMessages.get(0).isLogicallyInstantaneous()) {
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, linkedMessages.get(0));
+ }
+
+ if (requestQuery.isMultiSelectionOperation()) {
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, self, requestQuery.getISequenceEvents());
+ } else {
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, self);
+ }
+ if (linkedMessages.size() >= 2 && !linkedMessages.get(1).isLogicallyInstantaneous()) {
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, linkedMessages.get(1));
+ }
+ return ctc;
+ }
+
+ private boolean needVerticalSpaceExpansion(AbstractNodeEventResizeSelectionValidator validator, ChangeBoundsRequest request) {
+ return validator.getExpansionZone() != null && !new RequestQuery(request).isExecutionMovedIndirectly();
+ }
+
+ private Collection<ISequenceEvent> getSequenceEventsUpperToInsertionTime(SequenceDiagram sequenceDiagram, int lowerBound) {
+ Collection<ISequenceEvent> result = new ArrayList<ISequenceEvent>();
+ Set<AbstractNodeEvent> allDelimitedSequenceEvents = sequenceDiagram.getAllAbstractNodeEvents();
+ for (ISequenceEvent sequenceEvent : allDelimitedSequenceEvents) {
+ if (sequenceEvent.getVerticalRange().getLowerBound() > lowerBound) {
+ result.add(sequenceEvent);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Compute the current vertical move.
+ *
+ * @param cbr
+ * the current request.
+ * @return the vertical move.
+ */
+ protected Integer getVMove(ChangeBoundsRequest cbr) {
+ Rectangle logicalDelta = new RequestQuery(cbr).getLogicalDelta();
+ return logicalDelta.y;
+ }
+
+ private void addChildrenAdjustmentCommands(Execution exec, CompositeTransactionalCommand cc, TransactionalEditingDomain editingDomain, final ChangeBoundsRequest cbr,
+ AbstractNodeEventResizeSelectionValidator validator) {
+ RequestQuery rq = new RequestQuery(cbr);
+ Rectangle logicalDelta = rq.getLogicalDelta();
+ int moveDelta = logicalDelta.y;
+ int sizeDelta = logicalDelta.height;
+ if (rq.isResizeFromTop()) {
+ cc.compose(CommandFactory.createICommand(editingDomain, new ShiftDirectSubExecutionsOperation(exec, sizeDelta)));
+ cc.compose(CommandFactory.createICommand(editingDomain, new ShiftDescendantMessagesOperation(exec, moveDelta, true, false, true)));
+
+ addCompoundEventsMoveCommands(exec, cc, editingDomain, true, moveDelta, cbr, validator);
+ addCompoundEventsMoveCommands(exec, cc, editingDomain, false, 0, cbr, validator);
+ } else if (rq.isResizeFromBottom()) {
+ cc.compose(CommandFactory.createICommand(editingDomain, new ShiftDescendantMessagesOperation(exec, sizeDelta, true, false, false)));
+
+ addCompoundEventsMoveCommands(exec, cc, editingDomain, true, 0, cbr, validator);
+ addCompoundEventsMoveCommands(exec, cc, editingDomain, false, sizeDelta, cbr, validator);
+ }
+ }
+
+ private void addCompoundEventsMoveCommands(Execution self, CompositeTransactionalCommand cc, TransactionalEditingDomain editingDomain, final boolean top, int height, ChangeBoundsRequest request,
+ AbstractNodeEventResizeSelectionValidator validator) {
+ List<EventEnd> findEnds = EventEndHelper.findEndsFromSemanticOrdering(self);
+ RequestQuery rq = new RequestQuery(request);
+
+ final Range oldRange = self.getVerticalRange();
+ final int movedBound = top ? oldRange.getLowerBound() : oldRange.getUpperBound();
+ final EObject sem = self.getSemanticTargetElement().get();
+ final Predicate<SingleEventEnd> toMove = new Predicate<SingleEventEnd>() {
+ public boolean apply(SingleEventEnd input) {
+ return !input.getSemanticEvent().equals(sem);
+ }
+ };
+ final Predicate<EventEnd> moved = new Predicate<EventEnd>() {
+ public boolean apply(EventEnd input) {
+ return EventEndHelper.getSingleEventEnd(input, sem).isStart() == top;
+ }
+ };
+
+ SequenceDiagram sequenceDiagram = self.getDiagram();
+ for (CompoundEventEnd cee : Iterables.filter(Iterables.filter(findEnds, moved), CompoundEventEnd.class)) {
+ for (SingleEventEnd see : Iterables.filter(Lists.newArrayList(cee.getEventEnds()), toMove)) {
+ final ISequenceEvent ise = EventEndHelper.findISequenceEvent(see, sequenceDiagram);
+ if (ise == null) {
+ continue;
+ }
+
+ final Range seeRange = ise.getVerticalRange();
+ int lDelta = 0;
+ int uDelta = 0;
+ if (seeRange.getLowerBound() == movedBound && doNotMoveSourceOfReturnMessageOfReflexiveSyncCall(self, ise, rq)) {
+ lDelta = height;
+ if (new ISequenceEventQuery(ise).isReflectiveMessage() && getSelection(ise) == EditPart.SELECTED_NONE) {
+ // A reflexive message does not have the same lower and
+ // upper bound but both bound have to be moved like
+ // "normal" messages
+ uDelta = height;
+ }
+ }
+ if (seeRange.getUpperBound() == movedBound && doNotMoveTargetOfStartMessageOfReflexiveSyncCall(self, ise, rq)) {
+ uDelta = height;
+ if (new ISequenceEventQuery(ise).isReflectiveMessage() && getSelection(ise) == EditPart.SELECTED_NONE) {
+ // A reflexive message does not have the same lower and
+ // upper bound but both bound have to be moved like
+ // "normal" messages
+ lDelta = height;
+ }
+ }
+
+ if ((seeRange.getLowerBound() + lDelta) <= (seeRange.getUpperBound() + uDelta)) {
+ final Range newRange = new Range(seeRange.getLowerBound() + lDelta, seeRange.getUpperBound() + uDelta);
+ if (ise instanceof Message && !hasBothEndMoving((Message) ise)) {
+ Message msg = (Message) ise;
+ addMessageReconnectionCommand(self, cc, editingDomain, msg, newRange, request, validator);
+ } else {
+ cc.compose(CommandFactory.createICommand(editingDomain, new SetVerticalRangeOperation(ise, newRange)));
+ }
+ } else {
+ cc.compose(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
+ }
+ }
+ }
+ }
+
+ private int getSelection(ISequenceElement ise) {
+ Map<?, ?> editPartRegistry = getHost().getViewer().getEditPartRegistry();
+ Object object = editPartRegistry.get(ise.getNotationView());
+ if (object instanceof EditPart) {
+ return ((EditPart) object).getSelected();
+ }
+ return Integer.MIN_VALUE;
+ }
+
+ private void addMessageReconnectionCommand(Execution self, CompositeTransactionalCommand cc, TransactionalEditingDomain editingDomain, Message message, Range newRange,
+ ChangeBoundsRequest request, AbstractNodeEventResizeSelectionValidator validator) {
+
+ Set<Execution> executionsInMove = new RequestQuery(request).getExecutions();
+ boolean invalidCommand = false;
+
+ Predicate<EventEnd> filterCompoundEventEnd = new Predicate<EventEnd>() {
+ public boolean apply(EventEnd input) {
+ return input instanceof CompoundEventEnd;
+ }
+ };
+
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation((Edge) message.getNotationView(), newRange);
+
+ Lifeline selfLifeline = self.getLifeline().get();
+ Rectangle logicalDelta = new RequestQuery(request).getLogicalDelta();
+ Rectangle bounds = self.getProperLogicalBounds().getCopy();
+ bounds.translate(logicalDelta.getLocation());
+ bounds.resize(logicalDelta.getSize());
+ Range thisFinalRange = Range.verticalRange(bounds);
+
+ List<ISequenceEvent> toIgnore = Lists.newArrayList();
+ boolean isReplyMessage = message.getKind() == Message.Kind.REPLY;
+ boolean isReflective = message.isReflective();
+ ISequenceNode sourceElement = message.getSourceElement();
+ ISequenceNode targetElement = message.getTargetElement();
+ if (!isReplyMessage && isReflective && Iterables.any(EventEndHelper.findEndsFromSemanticOrdering(message), filterCompoundEventEnd) && targetElement == self) {
+ // Avoid target of the return message of a reflexive sync call to
+ // reconnect on its execution
+ toIgnore.add(self);
+ }
+ // if a verticalSpaceExpansion will occurs, ignore ISequenceEvent under
+ // the insertionPoint
+ if (needVerticalSpaceExpansion(validator, request)) {
+ Collection<ISequenceEvent> sequenceEventsUpperToInsertionTime = getSequenceEventsUpperToInsertionTime(self.getDiagram(), validator.getExpansionZone().getLowerBound());
+ sequenceEventsUpperToInsertionTime.removeAll(executionsInMove);
+ toIgnore.addAll(sequenceEventsUpperToInsertionTime);
+ }
+
+ Option<Lifeline> srcLifeline = message.getSourceLifeline();
+ if (srcLifeline.some()) {
+ EventFinder srcFinder = new EventFinder(srcLifeline.get());
+ srcFinder.setReconnection(true);
+ srcFinder.setEventsToIgnore(Predicates.in(toIgnore));
+ srcFinder.setExpansionZone(validator.getExpansionZone());
+ ISequenceEvent finalSrc = (srcLifeline.get() == selfLifeline && sourceElement == self) ? self : srcFinder.findMostSpecificEvent(newRange);
+ Range finalSrcRange = (srcLifeline.get() == selfLifeline && sourceElement == self) ? thisFinalRange : finalSrc.getVerticalRange();
+ smrc.setSource(finalSrc.getNotationView(), new Rectangle(0, finalSrcRange.getLowerBound(), 0, finalSrcRange.width()));
+ } else {
+ Range finalSrcRange = Range.verticalRange(sourceElement.getProperLogicalBounds());
+ smrc.setSource(sourceElement.getNotationView(), new Rectangle(0, finalSrcRange.getLowerBound(), 0, finalSrcRange.width()));
+ }
+
+ toIgnore.clear();
+ if (isReplyMessage && isReflective && Iterables.any(EventEndHelper.findEndsFromSemanticOrdering(message), filterCompoundEventEnd) && sourceElement == self) {
+ // Avoid target of the return message of a reflexive sync call to
+ // reconnect on its execution
+ toIgnore.add(self);
+ }
+ // if a verticalSpaceExpansion will occurs, ignore ISequenceEvent under
+ // the insertionPoint
+ if (needVerticalSpaceExpansion(validator, request)) {
+ Collection<ISequenceEvent> sequenceEventsUpperToInsertionTime = getSequenceEventsUpperToInsertionTime(self.getDiagram(), validator.getExpansionZone().getLowerBound());
+ sequenceEventsUpperToInsertionTime.removeAll(executionsInMove);
+ toIgnore.addAll(sequenceEventsUpperToInsertionTime);
+ }
+
+ Option<Lifeline> tgtLifeline = message.getTargetLifeline();
+ if (tgtLifeline.some()) {
+ EventFinder tgtFinder = new EventFinder(tgtLifeline.get());
+ tgtFinder.setReconnection(true);
+ tgtFinder.setEventsToIgnore(Predicates.in(toIgnore));
+ tgtFinder.setExpansionZone(validator.getExpansionZone());
+ ISequenceEvent finalTgt = (tgtLifeline.get() == selfLifeline && targetElement == self) ? self : tgtFinder.findMostSpecificEvent(newRange);
+ if (finalTgt == null) {
+ invalidCommand = true;
+ } else {
+ Range finalTgtRange = (tgtLifeline.get() == selfLifeline && targetElement == self) ? thisFinalRange : finalTgt.getVerticalRange();
+ smrc.setTarget(finalTgt.getNotationView(), new Rectangle(0, finalTgtRange.getLowerBound(), 0, finalTgtRange.width()));
+ }
+ } else {
+ Range finalTgtRange = Range.verticalRange(targetElement.getProperLogicalBounds());
+ smrc.setTarget(targetElement.getNotationView(), new Rectangle(0, finalTgtRange.getLowerBound(), 0, finalTgtRange.width()));
+ }
+
+ if (invalidCommand) {
+ cc.compose(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
+ } else {
+ cc.compose(CommandFactory.createICommand(editingDomain, smrc));
+ }
+
+ }
+
+ private boolean hasBothEndMoving(Message smep) {
+ Set<Execution> movingExecutionEditPart = getMovingExecutions();
+ return movingExecutionEditPart.contains(smep.getSourceElement()) && movingExecutionEditPart.contains(smep.getTargetElement());
+ }
+
+ private Set<Execution> getMovingExecutions() {
+ EditPartViewer viewer = getHost().getViewer();
+ Set<Execution> movingExecutions = Sets.newHashSet();
+ for (ExecutionEditPart eep : Iterables.filter(viewer.getSelectedEditParts(), ExecutionEditPart.class)) {
+ Execution exec = (Execution) eep.getISequenceEvent();
+ movingExecutions.add(exec);
+ movingExecutions.addAll(exec.findLinkedExecutions(true));
+ }
+
+ ArrayList<Execution> subExecutions = Lists.newArrayList();
+ for (Execution eep : movingExecutions) {
+ subExecutions.addAll(new ISequenceEventQuery(eep).getAllExecutions());
+ }
+ movingExecutions.addAll(subExecutions);
+ return movingExecutions;
+ }
+
+ /**
+ * Avoid moving the source of the return message of a reflexive synchronous
+ * message when resizing a parent execution.
+ *
+ * @param ise
+ * the sequence event to validate if it is a reflexive message we
+ * do not want to move
+ * @return the validation result of the message move.
+ */
+ private boolean doNotMoveSourceOfReturnMessageOfReflexiveSyncCall(Execution self, ISequenceEvent ise, RequestQuery rq) {
+ return !(isMovedReflexiveMessage(ise, rq) && self.equals(((Message) ise).getSourceElement()) && getSelection(((Message) ise).getSourceElement()) == EditPart.SELECTED_NONE && getSelection(ise) == EditPart.SELECTED_NONE);
+ }
+
+ /**
+ * Avoid moving the target of the invocation message of a reflexive
+ * synchronous message when resizing a parent execution.
+ *
+ * @param ise
+ * the sequence event to validate if it is a reflexive message we
+ * do not want to move
+ * @return the validation result of the message move.
+ */
+ private boolean doNotMoveTargetOfStartMessageOfReflexiveSyncCall(Execution self, ISequenceEvent ise, RequestQuery rq) {
+ return !(isMovedReflexiveMessage(ise, rq) && self.equals(((Message) ise).getTargetElement()) && getSelection(((Message) ise).getTargetElement()) == EditPart.SELECTED_NONE && getSelection(ise) == EditPart.SELECTED_NONE);
+ }
+
+ private boolean isMovedReflexiveMessage(ISequenceEvent ise, RequestQuery rq) {
+ return rq.isResize() && new ISequenceEventQuery(ise).isReflectiveMessage();
+ }
+
+ /*
+ * Feedback
+ */
+ /**
+ * Show/update the horizontal feedback lines aligned on the top and bottom
+ * of the execution.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+ eraseChangeBoundsFeedback(request);
+ super.showChangeBoundsFeedback(request);
+
+ ExecutionEditPart hostPart = (ExecutionEditPart) getHost();
+ AbstractNodeEvent host = (AbstractNodeEvent) hostPart.getISequenceEvent();
+ RequestQuery requestQuery = new RequestQuery(request);
+
+ if (hostPart.getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isMove()) {
+ ISEComplexMoveValidator validator = ISEComplexMoveValidator.getOrCreateValidator(request, requestQuery, host);
+ if (validator != null) {
+ SequenceInteractionFeedBackBuilder feedBackBuilder = new SequenceInteractionFeedBackBuilder(validator, getFeedbackLayer(), hostPart);
+ for (Figure fig : feedBackBuilder.buildFeedBack()) {
+ addFeedback(fig);
+ guides.add(fig);
+ }
+ }
+ } else if (requestQuery.isResize()) {
+ AbstractNodeEventResizeSelectionValidator validator = AbstractNodeEventResizeSelectionValidator.getOrCreateValidator(request, host);
+ validator.validate();
+ showResizeFeedBack(request);
+ feedBack(validator);
+ }
+ }
+
+ /**
+ * Show feedback for computed conflicts during validation.
+ *
+ * @param validator
+ * the current resize validator.
+ */
+ protected void feedBack(AbstractNodeEventResizeSelectionValidator validator) {
+ IFigure feedbackLayer = getFeedbackLayer();
+ for (Integer conflict : validator.getInvalidPositions()) {
+ Point conflictingPosition = new Point(0, conflict);
+ conflictingPosition.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+
+ Rectangle bounds = feedbackLayer.getBounds().getCopy();
+ bounds.y = conflictingPosition.y;
+ bounds.height = 1;
+
+ HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+ conflictGuide.setBounds(bounds);
+ addFeedback(conflictGuide);
+ guides.add(conflictGuide);
+ }
+
+ Range expansionZone = validator.getExpansionZone();
+ if (expansionZone != null && !expansionZone.isEmpty() && expansionZone.width() != 0) {
+ Rectangle screenRange = new Rectangle(0, expansionZone.getLowerBound(), 0, expansionZone.width());
+ screenRange.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+ Range expand = Range.verticalRange(screenRange);
+
+ Rectangle bounds = feedbackLayer.getBounds().getCopy();
+ bounds.height = expand.width();
+ bounds.y = expand.getLowerBound();
+
+ RangeGuide expansion = new RangeGuide(validator.isValid() ? ColorConstants.blue : ColorConstants.red, expand, true);
+ expansion.setBounds(bounds);
+ addFeedback(expansion);
+ guides.add(expansion);
+ }
+ }
+
+ /**
+ * Show feedback for resize.
+ *
+ * @param request
+ * the current resize request.
+ */
+ protected void showResizeFeedBack(ChangeBoundsRequest request) {
+ // TODO Refactor this and share the code with
+ // SequenceMessageEditPolicy
+ // and put in a graphical edit policy to inherit instead of copy the
+ // feedback utility methods.
+
+ Rectangle oldBounds = getHostAbsoluteBounds().getCopy();
+ Rectangle newBounds = request.getTransformedRectangle(oldBounds).getCopy();
+ Rectangle execBounds = newBounds.getCopy();
+
+ FreeformViewport viewport = FigureUtilities.getFreeformViewport(getHostFigure());
+ if (viewport != null) {
+ oldBounds.translate(viewport.getViewLocation());
+ newBounds.translate(viewport.getViewLocation());
+ }
+
+ if (getHost() instanceof ExecutionEditPart && newBounds.height > 0) {
+ ISequenceEvent iSequenceEvent = ((ISequenceEventEditPart) getHost()).getISequenceEvent();
+ GraphicalHelper.screen2logical(newBounds, (IGraphicalEditPart) getHost());
+ GraphicalHelper.screen2logical(oldBounds, (IGraphicalEditPart) getHost());
+ Range oldRange = Range.verticalRange(oldBounds);
+ Range execRange = Range.verticalRange(newBounds);
+ Range fullFinalRange = Range.verticalRange(newBounds);
+ List<ISequenceEvent> delimitingMessages = EventEndHelper.getCompoundEvents(iSequenceEvent);
+ if (delimitingMessages.size() > 0) {
+ ISequenceEvent callMessage = delimitingMessages.get(0);
+ Range callMsgRange = callMessage.getVerticalRange();
+ if (request.isConstrainedMove()) {
+ fullFinalRange = new Range(oldRange.getLowerBound() - callMsgRange.width(), fullFinalRange.getUpperBound());
+ } else {
+ fullFinalRange = new Range(fullFinalRange.getLowerBound() - callMsgRange.width(), fullFinalRange.getUpperBound());
+ }
+ }
+ if (delimitingMessages.size() > 1) {
+ ISequenceEvent returnMessage = delimitingMessages.get(1);
+ Range returnMsgRange = returnMessage.getVerticalRange();
+ if (request.isConstrainedResize()) {
+ fullFinalRange = new Range(fullFinalRange.getLowerBound(), oldRange.getUpperBound() + returnMsgRange.width());
+ } else {
+ fullFinalRange = new Range(fullFinalRange.getLowerBound(), fullFinalRange.getUpperBound() + returnMsgRange.width());
+ }
+ }
+ newBounds = new Rectangle(0, fullFinalRange.getLowerBound(), 0, fullFinalRange.width());
+ execBounds = new Rectangle(0, execRange.getLowerBound(), 0, execRange.width());
+
+ if (iSequenceEvent.isLogicallyInstantaneous() && delimitingMessages.isEmpty()) {
+ execBounds.y = execBounds.getCenter().y;
+ execBounds.height = 1;
+
+ newBounds = execBounds.getCopy();
+ }
+
+ GraphicalHelper.logical2screen(newBounds, (IGraphicalEditPart) getHost());
+ GraphicalHelper.logical2screen(execBounds, (IGraphicalEditPart) getHost());
+ }
+
+ Point topLocation = new Point(1, newBounds.getTop().y);
+ Point bottomLocation = new Point(1, newBounds.getBottom().y);
+
+ Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+ execBounds.height = Math.max(execBounds.height, 0);
+
+ Figure execGuide = new RangeGuide(EXECUTION_FEEDBACK_COLOR, Range.verticalRange(execBounds), false);
+ bounds.height = execBounds.height + 1;
+ bounds.y = execBounds.y;
+ execGuide.setBounds(bounds);
+ addFeedback(execGuide);
+ guides.add(execGuide);
+
+ if (execBounds.y != topLocation.y) {
+ Figure topGuide = new HorizontalGuide(EXECUTION_FEEDBACK_COLOR, topLocation.y);
+ bounds.height = 1;
+ bounds.y = topLocation.y;
+ topGuide.setBounds(bounds);
+ addFeedback(topGuide);
+ guides.add(topGuide);
+ }
+
+ if (execBounds.bottom() != bottomLocation.y) {
+ bounds = getFeedbackLayer().getBounds().getCopy();
+ Figure bottomGuide = new HorizontalGuide(EXECUTION_FEEDBACK_COLOR, bottomLocation.y);
+ bounds.height = 1;
+ bounds.y = bottomLocation.y;
+ bottomGuide.setBounds(bounds);
+ addFeedback(bottomGuide);
+ guides.add(bottomGuide);
+ }
+ }
+
+ private Rectangle getHostAbsoluteBounds() {
+ Rectangle bounds = getHostFigure().getBounds().getCopy();
+ getHostFigure().getParent().translateToAbsolute(bounds);
+ return bounds;
+ }
+
+ private void removeFeedBackOnGuides() {
+ if (guides != null && !guides.isEmpty()) {
+ for (Figure hGuide : guides) {
+ removeFeedback(hGuide);
+ }
+ guides.clear();
+ }
+ }
+
+ /**
+ * Remove the horizontal feedback lines.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected void eraseChangeBoundsFeedback(ChangeBoundsRequest request) {
+ removeFeedBackOnGuides();
+ super.eraseChangeBoundsFeedback(request);
+ }
+
+ /**
+ * Cancel horizontal changes of the given request.
+ *
+ * @param request
+ * a request.
+ */
+ protected void cancelHorizontalDelta(ChangeBoundsRequest request) {
+ if (request == null) {
+ return;
+ }
+
+ Point moveDelta = request.getMoveDelta();
+ if (moveDelta != null) {
+ request.setMoveDelta(new Point(0, moveDelta.y));
+ }
+
+ Dimension sizeDelta = request.getSizeDelta();
+ if (sizeDelta != null) {
+ request.setSizeDelta(new Dimension(0, sizeDelta.height));
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java
new file mode 100644
index 0000000000..eaccc0e508
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ExecutionSemanticEditPolicy.java
@@ -0,0 +1,336 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.LayerConstants;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.editparts.LayerManager;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gef.requests.CreateConnectionRequest;
+import org.eclipse.gef.requests.CreateRequest;
+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.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.emf.type.core.commands.DestroyElementCommand;
+import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.description.style.NodeStyleDescription;
+import org.eclipse.sirius.description.style.SquareDescription;
+import org.eclipse.sirius.description.style.WorkspaceImageDescription;
+import org.eclipse.sirius.diagram.internal.edit.policies.DNode2ItemSemanticEditPolicy;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.tool.ToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.description.EndOfLifeMapping;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.RangeGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutUtils;
+import org.eclipse.sirius.diagram.ui.tools.internal.util.EditPartQuery;
+
+/**
+ * A specialized semantic edit policy for sequence diagram elements.
+ * <ul>
+ * <li>Overrides the REQ_CONNECTION_END to invoke the appropriate message
+ * creation tool with the additional variables required for its insertion at the
+ * right place in the semantic model.</li>
+ * <li>Shows horizontal feedback lines when an execution is moved/resized.</li>
+ * </ul>
+ *
+ * @author pcdavid
+ */
+public class ExecutionSemanticEditPolicy extends DNode2ItemSemanticEditPolicy {
+
+ private RangeGuide forbiddenRangeArea;
+
+ /**
+ * Overridden to handle the REQ_CONNECTION_END specially as the location at
+ * which a message is created has a semantic meaning.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public Command getCommand(final Request request) {
+ Command superCommand = super.getCommand(request);
+ Command command = customizeEndOfLifeCreationCommand(request, superCommand);
+ return command;
+ }
+
+ private Command customizeEndOfLifeCreationCommand(final Request request, Command superCommand) {
+ Command command;
+ command = superCommand;
+
+ if (request instanceof CreateViewRequest) {
+ CreateViewRequest cvr = (CreateViewRequest) request;
+ EndOfLifeMapping endOfLifeMapping = getEndOfLifeMapping(cvr);
+ if (cvr.getLocation().x == -1 && cvr.getLocation().y == -1 && endOfLifeMapping != null) {
+ // adding an EndOfLifeEditPart will resize the RootExecution
+ // to
+ // keep the same global size on the lifeline
+ String label = superCommand != null ? superCommand.getLabel() : "";
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(getEditingDomain(), label);
+
+ if (superCommand != null) {
+ ctc.compose(new CommandProxy(superCommand));
+ }
+
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ cbr.setResizeDirection(PositionConstants.SOUTH);
+ cbr.getSizeDelta().height = -calculateHalfSizeOfEndOfLifeEditPartToCreate(endOfLifeMapping);
+ ctc.compose(new CommandProxy(getHost().getCommand(cbr)));
+
+ ICommandProxy iCommandProxy = new ICommandProxy(ctc);
+ iCommandProxy.setLabel(ctc.getLabel());
+ command = iCommandProxy;
+ }
+ }
+ return command;
+ }
+
+ /**
+ * Calculate the half size of the EndOfLifeEditPart that will be created.
+ *
+ * @param request
+ * the request to create a new connection targeting an
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart}
+ * @return half the size of the EndOfLifeEditPart that will be created
+ */
+ private int calculateHalfSizeOfEndOfLifeEditPartToCreate(EndOfLifeMapping endOfLifeMapping) {
+ NodeStyleDescription style = endOfLifeMapping.getStyle();
+ int halfsize = 0;
+ if (style instanceof SquareDescription) {
+ SquareDescription sd = (SquareDescription) style;
+ halfsize = (sd.getHeight() * LayoutUtils.SCALE) / 2;
+ if (halfsize < LayoutUtils.SCALE) {
+ // minimum size displayed
+ halfsize = LayoutUtils.SCALE;
+ }
+ } else if (style instanceof WorkspaceImageDescription) {
+ WorkspaceImageDescription wid = (WorkspaceImageDescription) style;
+ String sizeComputationExpression = wid.getSizeComputationExpression();
+ Integer sizeComputationInteger = Integer.valueOf(sizeComputationExpression);
+ if (sizeComputationInteger != null) {
+ halfsize = (sizeComputationInteger * LayoutUtils.SCALE) / 2;
+ }
+ }
+ return halfsize;
+ }
+
+ /**
+ * Overridden to have feedback on forbidden combined fragment header range.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void showTargetFeedback(Request request) {
+ removeForbiddenRangeFeedback();
+
+ if (request instanceof CreateRequest && ((CreateRequest) request).getLocation() != null) {
+ ISequenceEventEditPart host = (ISequenceEventEditPart) getHost();
+ ISequenceEvent sequenceEvent = host.getISequenceEvent();
+ SequenceDiagram sequenceDiagram = sequenceEvent.getDiagram();
+
+ CreateRequest createRequest = (CreateRequest) request;
+ Point location = createRequest.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+ EventEnd startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDiagram.getSequenceDDiagram(), location.y);
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(sequenceDiagram, startingEndPredecessor) && startingEndPredecessor instanceof SingleEventEnd) {
+ IFigure layer = getFeedbackLayer();
+ // show forbidden range
+ SingleEventEnd singleEventEnd = (SingleEventEnd) startingEndPredecessor;
+ ISequenceEvent ise = EventEndHelper.findISequenceEvent(singleEventEnd, sequenceDiagram);
+ if (layer != null && ise instanceof CombinedFragment) {
+ Range verticalRange = ise.getVerticalRange();
+ Rectangle screenRange = new Rectangle(0, verticalRange.getLowerBound(), 0, LayoutConstants.COMBINED_FRAGMENT_TITLE_HEIGHT);
+ screenRange.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+ Range forbiddenRange = Range.verticalRange(screenRange);
+
+ forbiddenRangeArea = new RangeGuide(ColorConstants.red, forbiddenRange, true);
+ Rectangle bounds = layer.getBounds().getCopy();
+ bounds.height = forbiddenRange.width();
+ bounds.y = forbiddenRange.getLowerBound();
+ forbiddenRangeArea.setBounds(bounds);
+ layer.add(forbiddenRangeArea);
+ }
+ } else {
+ super.showTargetFeedback(request);
+ }
+ } else {
+ super.showTargetFeedback(request);
+ }
+ }
+
+ /**
+ * Overridden to erase feedback of forbidden combined fragment header range.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void eraseTargetFeedback(Request request) {
+ removeForbiddenRangeFeedback();
+
+ super.eraseTargetFeedback(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPart getTargetEditPart(Request request) {
+ EditPart result = super.getTargetEditPart(request);
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (request instanceof CreateConnectionRequest && requestQuery.isStandardMessageCreation() && getHost() instanceof ISequenceEventEditPart
+ && org.eclipse.gef.RequestConstants.REQ_CONNECTION_END.equals(request.getType())) {
+ CreateConnectionRequest createRequest = (CreateConnectionRequest) request;
+ ISequenceEventEditPart ise = (ISequenceEventEditPart) getHost();
+
+ if (ise instanceof ExecutionEditPart) {
+ ise = new EditPartQuery(ise).getFirstAncestorOfType(LifelineEditPart.class);
+ } else if (!(ise instanceof LifelineEditPart)) {
+ ise = null;
+ }
+
+ EditPart source = createRequest.getSourceEditPart();
+ if (source instanceof ExecutionEditPart) {
+ source = new EditPartQuery((IGraphicalEditPart) source).getFirstAncestorOfType(LifelineEditPart.class);
+ } else if (!(source instanceof LifelineEditPart)) {
+ source = null;
+ }
+
+ // if ise lifeline equals source lifeline : reflexive message
+ if (ise != null && !ise.equals(source)) {
+ Point firstClickLocation = SequenceEditPartsOperations.getConnectionSourceLocation(createRequest, ise);
+ if (firstClickLocation != null) {
+ GraphicalHelper.screen2logical(firstClickLocation, ise);
+
+ ISequenceEvent sequenceEvent = ise.getISequenceEvent();
+ Range targetRange = sequenceEvent.getVerticalRange();
+ for (ExecutionEditPart potentialTarget : EditPartsHelper.getAllExecutions(ise)) {
+ Range range = potentialTarget.getISequenceEvent().getVerticalRange();
+ if (targetRange.includes(range) && range.includes(firstClickLocation.y)) {
+ targetRange = range;
+ result = potentialTarget;
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Investigate the request to return the EndOfLifeMapping if existent
+ *
+ * @param createViewRequest
+ * the current request
+ * @return the EndOfLifeMapping if existent
+ */
+ private EndOfLifeMapping getEndOfLifeMapping(CreateViewRequest createViewRequest) {
+ Iterable<ViewDescriptor> filter = Iterables.filter(createViewRequest.getViewDescriptors(), ViewDescriptor.class);
+ for (ViewDescriptor viewDescriptor : filter) {
+ IAdaptable elementAdapter = viewDescriptor.getElementAdapter();
+ if (elementAdapter instanceof EObjectAdapter) {
+ EObjectAdapter eobjectAdapter = (EObjectAdapter) elementAdapter;
+ Object realObject = eobjectAdapter.getRealObject();
+ if (realObject instanceof DNode) {
+ DNode dns = (DNode) realObject;
+ NodeMapping actualMapping = dns.getActualMapping();
+ if (actualMapping instanceof EndOfLifeMapping) {
+ return (EndOfLifeMapping) actualMapping;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * .
+ *
+ * @param sequenceElement
+ * .
+ * @param sequenceDiagram
+ * .
+ * @param firstClickLocation
+ * .
+ * @param secondClickLocation
+ * .
+ * @return .
+ */
+ public static boolean isCombinedFragmentTitleRangeEdgeCreation(ISequenceElement sequenceElement, SequenceDiagram sequenceDiagram, Point firstClickLocation, Point secondClickLocation) {
+ boolean result = false;
+ EventEnd startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDiagram.getSequenceDDiagram(), firstClickLocation.y);
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(sequenceDiagram, startingEndPredecessor)) {
+ result = true;
+ }
+
+ EventEnd finishingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDiagram.getSequenceDDiagram(), secondClickLocation.y);
+ if (ToolCommandBuilder.isStartingEventEndOfCombinedFragment(sequenceDiagram, finishingEndPredecessor)) {
+ result = true;
+ }
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getDestroyElementCommand(DestroyElementRequest req) {
+ CompoundCommand cc = new CompoundCommand();
+ addDestroyChildNodesCommand(cc);
+ addDestroyShortcutsCommand(cc);
+ cc.add(getGEFWrapper(new DestroyElementCommand(req)));
+ return cc.unwrap();
+ }
+
+ private void removeForbiddenRangeFeedback() {
+ IFigure layer = getFeedbackLayer();
+ if (forbiddenRangeArea != null && layer.getChildren().contains(forbiddenRangeArea)) {
+ layer.remove(forbiddenRangeArea);
+ }
+ }
+
+ private IFigure getFeedbackLayer() {
+ IFigure layer = LayerManager.Helper.find(getHost()).getLayer(LayerConstants.FEEDBACK_LAYER);
+ return layer;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/FrameAwareContainerCreationPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/FrameAwareContainerCreationPolicy.java
new file mode 100644
index 0000000000..0edd40a338
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/FrameAwareContainerCreationPolicy.java
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.LayerConstants;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.editparts.LayerManager;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+import org.eclipse.sirius.diagram.graphical.edit.policies.ContainerCreationEditPolicy;
+import org.eclipse.sirius.diagram.graphical.edit.policies.CreationUtil;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.VerticalSpaceExpansion;
+import org.eclipse.sirius.diagram.sequence.description.tool.CombinedFragmentCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InteractionUseCreationTool;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command.SequenceDelegatingCommandFactory;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.FrameCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.CreateRequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.command.DoNothingCommand;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+
+/**
+ * An extension of the standard Sirius ContainerCreationEditPolicy which
+ * knows how to handle the specific tools use to create frames (i.e. Interaction
+ * Uses and Combined Fragments).
+ *
+ * @author pcdavid
+ */
+public class FrameAwareContainerCreationPolicy extends ContainerCreationEditPolicy {
+
+ /** Label use for the Interaction Use creation. */
+ public static final String INTERACTION_USE_CREATION_CMD_LABEL = "Interaction Use creation";
+
+ /** Label use for the Combined Fragment creation. */
+ public static final String COMBINED_FRAGMENT_CREATION_CMD_LABEL = "Combined Fragment creation";
+
+ /**
+ * Additional figures for feedback.
+ */
+ protected Collection<Figure> guides = Lists.newArrayList();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getCreateContainerOnDiagramCommand(CreateRequest request, ContainerCreationDescription ccdTool, DDiagram diagram) {
+ Command result;
+
+ boolean frameCreationTool = ccdTool instanceof InteractionUseCreationTool || ccdTool instanceof CombinedFragmentCreationTool;
+ if (frameCreationTool && getHost() instanceof SequenceDiagramEditPart && diagram instanceof SequenceDDiagram) {
+ SequenceDiagramEditPart sdep = (SequenceDiagramEditPart) getHost();
+ TransactionalEditingDomain domain = sdep.getEditingDomain();
+ Diagram gmfDiagram = sdep.getDiagramView();
+ SequenceDiagram sequenceDiagram = ISequenceElementAccessor.getSequenceDiagram(gmfDiagram).get();
+ FrameCreationValidator creationValidator = FrameCreationValidator.getOrCreateValidator(sequenceDiagram, ccdTool, new CreateRequestQuery(request, sdep));
+
+ if (creationValidator.isValid()) {
+ EventEnd startingEndPredecessor = creationValidator.getStartingEndPredecessor();
+ EventEnd finishingEndPredecessor = creationValidator.getFinishingEndPredecessor();
+ List<EObject> coverage = creationValidator.getCoverage();
+ Range expansionZone = creationValidator.getExpansionZone();
+
+ CreationUtil creationUtil = new CreationUtil(request, getDiagramCommandFactory(startingEndPredecessor, finishingEndPredecessor, coverage, getCreationRange(request)),
+ getRealLocation(request), getRealSize(ccdTool, request), getHost());
+ result = creationUtil.getContainerCreationDescription(diagram, ccdTool);
+
+ // Add a vertical expansion command if we do inclusion
+ if (expansionZone != null && !expansionZone.isEmpty() && result != null && result.canExecute()) {
+ // Shift the element to not include int the range of the
+ // AbstractFrame to create
+ VerticalSpaceExpansion verticalSpaceExpansion = new VerticalSpaceExpansion(sequenceDiagram, expansionZone, 0, Collections.<ISequenceEvent> emptyList());
+ ICommand expandSubEventsCmd = CommandFactory.createICommand(domain, verticalSpaceExpansion);
+
+ result = new ICommandProxy(expandSubEventsCmd).chain(result);
+ }
+ if (result != null) {
+ if (ccdTool instanceof InteractionUseCreationTool) {
+ result.setLabel(INTERACTION_USE_CREATION_CMD_LABEL);
+ } else if (ccdTool instanceof CombinedFragmentCreationTool) {
+ result.setLabel(COMBINED_FRAGMENT_CREATION_CMD_LABEL);
+ }
+ }
+ } else {
+ result = creationValidator.getCoverage().isEmpty() ? DoNothingCommand.INSTANCE : UnexecutableCommand.INSTANCE;
+ }
+ } else {
+ result = super.getCreateContainerOnDiagramCommand(request, ccdTool, diagram);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to show the feedback of the expansion zone for
+ * InteractionUse/CombinedFragment creation when there is inclusion of
+ * existing sequence events in its creation range and vertical space
+ * expansion is needed for some sequence events.
+ *
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void showTargetFeedback(Request request) {
+ eraseTargetFeedback(request);
+ if (request instanceof CreateRequest && this.getHost() instanceof SequenceDiagramEditPart) {
+ SequenceDiagramEditPart sdep = (SequenceDiagramEditPart) getHost();
+ CreateRequest createRequest = (CreateRequest) request;
+ Option<ISequenceElement> seqDiag = ISequenceElementAccessor.getISequenceElement((View) this.getHost().getModel());
+ AbstractToolDescription tool = getTool(createRequest);
+ if (seqDiag.some() && seqDiag.get() instanceof SequenceDiagram && tool instanceof InteractionUseCreationTool || tool instanceof CombinedFragmentCreationTool) {
+ FrameCreationValidator validator = FrameCreationValidator.getOrCreateValidator((SequenceDiagram) seqDiag.get(), (ContainerCreationDescription) tool, new CreateRequestQuery(
+ createRequest, sdep));
+ if (validator != null) {
+ SequenceInteractionFeedBackBuilder feedBackBuilder = new SequenceInteractionFeedBackBuilder(validator, getFeedbackLayer(), (IGraphicalEditPart) getHost());
+ for (Figure fig : feedBackBuilder.buildFeedBack()) {
+ addFeedback(fig);
+ guides.add(fig);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Overridden to erase feedback for AbstractFrame creation request.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void eraseTargetFeedback(Request request) {
+ removeFeedBackOnGuides();
+ }
+
+ private void removeFeedBackOnGuides() {
+ if (guides != null && !guides.isEmpty()) {
+ for (Figure hGuide : guides) {
+ removeFeedback(hGuide);
+ }
+ guides.clear();
+ }
+ }
+
+ /**
+ * Add a IFigure to the feedbackLayer.
+ *
+ * @param figure
+ * the feedback figure to add
+ */
+ protected void addFeedback(IFigure figure) {
+ getFeedbackLayer().add(figure);
+ }
+
+ /**
+ * Returns the layer used for displaying feedback.
+ *
+ * @return the feedback layer
+ */
+ protected IFigure getFeedbackLayer() {
+ return getLayer(LayerConstants.FEEDBACK_LAYER);
+ }
+
+ /**
+ * Convenience method to return the host's Figure.
+ *
+ * @return The host GraphicalEditPart's Figure
+ */
+ protected IFigure getHostFigure() {
+ return ((GraphicalEditPart) getHost()).getFigure();
+ }
+
+ /**
+ * Obtains the specified layer.
+ *
+ * @param layer
+ * the key identifying the layer
+ * @return the requested layer
+ */
+ protected IFigure getLayer(Object layer) {
+ return LayerManager.Helper.find(getHost()).getLayer(layer);
+ }
+
+ /**
+ * Removes the specified <code>Figure</code> from the
+ * {@link LayerConstants#FEEDBACK_LAYER}.
+ *
+ * @param figure
+ * the feedback to remove
+ */
+ protected void removeFeedback(IFigure figure) {
+ getFeedbackLayer().remove(figure);
+ }
+
+ private Range getCreationRange(CreateRequest request) {
+ Point realLocation = getRealLocation(request);
+ Range result = Range.emptyRange();
+ if (request.getSize() != null) {
+ result = new Range(realLocation.y, realLocation.y + request.getSize().height);
+ }
+ return result;
+ }
+
+ private Dimension getRealSize(ContainerCreationDescription ccdTool, CreateRequest request) {
+ Dimension realSize = request.getSize();
+ if (realSize == null) {
+ realSize = new Dimension(0, 0);
+ if (ccdTool instanceof InteractionUseCreationTool) {
+ realSize.height = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT;
+ } else if (ccdTool instanceof CombinedFragmentCreationTool) {
+ realSize.height = LayoutConstants.DEFAULT_COMBINED_FRAGMENT_HEIGHT;
+ }
+ }
+ return realSize;
+ }
+
+ private IDiagramCommandFactory getDiagramCommandFactory(EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor, List<EObject> coverage, Range creationRange) {
+ SequenceDiagram seqDiag = null;
+ EditPart host = getHost();
+ if (host instanceof SequenceDiagramEditPart) {
+ seqDiag = ((SequenceDiagramEditPart) host).getSequenceDiagram();
+ }
+
+ final DDiagramEditor diagramEditor = (DDiagramEditor) host.getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (diagramEditor == null || seqDiag == null) {
+ return null;
+ }
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(seqDiag.getNotationDiagram());
+ final Object adapter = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class);
+ final IDiagramCommandFactoryProvider cmdFactoryProvider = (IDiagramCommandFactoryProvider) adapter;
+ final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
+ return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor, coverage);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ISEComplexMoveCommandBuilder.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ISEComplexMoveCommandBuilder.java
new file mode 100644
index 0000000000..51ecc60087
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ISEComplexMoveCommandBuilder.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
+import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.notation.Edge;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.ISequenceNodeMoveOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.ReparentExecutionOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetMessageRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.VerticalSpaceExpansion;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ShiftMessagesOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.ISEComplexMoveValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * A builder for complex sequence move commands.
+ *
+ * @author mporhel
+ */
+public class ISEComplexMoveCommandBuilder {
+
+ private final TransactionalEditingDomain editingDomain;
+
+ private final String label;
+
+ private final RequestQuery requestQuery;
+
+ private final ISEComplexMoveValidator validator;
+
+ /**
+ * Constructor.
+ *
+ * @param editingDomain
+ * tue editing domain
+ * @param label
+ * the label of the command to build
+ * @param requestQuery
+ * a query corresponding to the current request
+ * @param validator
+ * the move validator.
+ */
+ public ISEComplexMoveCommandBuilder(TransactionalEditingDomain editingDomain, String label, RequestQuery requestQuery, ISEComplexMoveValidator validator) {
+ this.editingDomain = editingDomain;
+ this.label = label;
+ this.requestQuery = requestQuery;
+ this.validator = validator;
+ }
+
+ /**
+ * Build the command.
+ *
+ * @return a composite transactional command.
+ */
+ public CompositeTransactionalCommand buildCommand() {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(editingDomain, label);
+
+ Integer vMove = requestQuery.getLogicalDelta().y;
+ expandDiagram(ctc, vMove);
+ handleNodes(ctc, vMove);
+ handleMessages(ctc, vMove);
+
+ return ctc;
+ }
+
+ private void handleMessages(CompositeTransactionalCommand ctc, Integer vMove) {
+
+ shiftMessages(ctc, vMove);
+ resizeMessages(ctc, vMove);
+ reconnectMessages(ctc, vMove);
+
+ }
+
+ private void handleNodes(CompositeTransactionalCommand ctc, Integer vMove) {
+ Collection<ISequenceNode> seqNodesToMove = Lists.newArrayList(validator.getSequenceNodeToMove());
+ Map<AbstractNodeEvent, ISequenceEvent> reparents = Maps.newHashMap();
+
+ computeReparents(seqNodesToMove, reparents);
+
+ moveNodes(ctc, vMove, seqNodesToMove);
+ reparentNodes(ctc, vMove, reparents);
+ }
+
+ private void reconnectMessages(CompositeTransactionalCommand ctc, Integer vMove) {
+ for (Reconnection reconnection : computeReconnections()) {
+ Message message = reconnection.getMessage();
+ ISequenceNode source = reconnection.getSource();
+ ISequenceNode target = reconnection.getTarget();
+
+ Rectangle srcBounds = source.getProperLogicalBounds();
+ Rectangle tgtBounds = target.getProperLogicalBounds();
+ Collection<ISequenceEvent> movedElements = validator.getMovedElements();
+ if (movedElements.contains(source)) {
+ srcBounds = requestQuery.getLogicalTransformedRectangle(srcBounds);
+ }
+ if (movedElements.contains(target)) {
+ tgtBounds = requestQuery.getLogicalTransformedRectangle(tgtBounds);
+ }
+
+ Range newRange = movedElements.contains(message) ? message.getVerticalRange().shifted(vMove) : message.getVerticalRange();
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation((Edge) message.getNotationView(), newRange);
+ smrc.setSource(source.getNotationNode(), srcBounds);
+ smrc.setTarget(target.getNotationNode(), tgtBounds);
+ ctc.compose(CommandFactory.createICommand(editingDomain, smrc));
+ }
+ }
+
+ private void reparentNodes(CompositeTransactionalCommand ctc, Integer vMove, Map<AbstractNodeEvent, ISequenceEvent> reparents) {
+ for (Map.Entry<AbstractNodeEvent, ISequenceEvent> entry : reparents.entrySet()) {
+ ISequenceEvent newParent = entry.getValue();
+ ctc.compose(CommandFactory.createICommand(editingDomain, new ReparentExecutionOperation(entry.getKey(), newParent)));
+
+ // Compute the absolute bounds implied by the requested move.
+ Rectangle realLocation = entry.getKey().getProperLogicalBounds();
+ if (validator.getMovedElements().contains(entry.getKey())) {
+ realLocation = requestQuery.getLogicalTransformedRectangle(realLocation);
+ }
+
+ // Adjust x coordinate depending on the nature of the final parent.
+ Rectangle parentBounds = newParent.getProperLogicalBounds();
+ if (validator.getMovedElements().contains(newParent)) {
+ parentBounds = requestQuery.getLogicalTransformedRectangle(parentBounds);
+ }
+
+ Range futureRange = validator.getRangeFunction().apply(entry.getKey());
+ realLocation.y = futureRange.getLowerBound();
+
+ // Make the coordinates relative to the final parent's figure.
+ final Point parentOrigin = parentBounds.getLocation();
+ final Dimension d = realLocation.getTopLeft().getDifference(parentOrigin);
+ Point locationOnFinalParent = new Point(realLocation.x, d.height);
+
+ // Create the command to apply the change.
+ final ICommand moveCommand = new SetBoundsCommand(ctc.getEditingDomain(), DiagramUIMessages.Commands_MoveElement, new EObjectAdapter(entry.getKey().getNotationNode()), locationOnFinalParent);
+ ctc.compose(moveCommand);
+
+ }
+ }
+
+ private void shiftMessages(CompositeTransactionalCommand ctc, Integer vMove) {
+ ICommand messageMoveCommand = CommandFactory.createICommand(editingDomain, new ShiftMessagesOperation(validator.getMessageToMove(), validator.getMovedElements(), vMove, false, true));
+ ctc.add(messageMoveCommand);
+ }
+
+ private void resizeMessages(CompositeTransactionalCommand ctc, Integer vMove) {
+ for (Message msg : Iterables.concat(validator.getResizedStartMessages(), validator.getResizedEndMessages())) {
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation(msg.getNotationEdge(), validator.getRangeFunction().apply(msg));
+
+ ISequenceEvent src = (ISequenceEvent) msg.getSourceElement();
+ Range srcRange = validator.getRangeFunction().apply(src);
+ smrc.setSource(src.getNotationView(), new Rectangle(0, srcRange.getLowerBound(), 0, srcRange.getUpperBound()));
+
+ ISequenceEvent tgt = (ISequenceEvent) msg.getTargetElement();
+ Range tgtRange = validator.getRangeFunction().apply(tgt);
+ smrc.setTarget(tgt.getNotationView(), new Rectangle(0, tgtRange.getLowerBound(), 0, tgtRange.getUpperBound()));
+
+ ICommand resizeStartMessages = CommandFactory.createICommand(editingDomain, smrc);
+ ctc.add(resizeStartMessages);
+ }
+ }
+
+ private void moveNodes(CompositeTransactionalCommand ctc, Integer vMove, Collection<ISequenceNode> seqNodesToMove) {
+ ICommand moveExecCmd = CommandFactory.createICommand(editingDomain, new ISequenceNodeMoveOperation(seqNodesToMove, vMove));
+ ctc.compose(moveExecCmd);
+ ctc.setLabel(moveExecCmd.getLabel());
+ }
+
+ private void expandDiagram(CompositeTransactionalCommand ctc, Integer vMove) {
+ if (validator.getExpansionZone() != null && !validator.getExpansionZone().isEmpty()) {
+ ctc.compose(CommandFactory.createICommand(editingDomain, new VerticalSpaceExpansion(validator.getDiagram(), validator.getExpansionZone(), vMove, validator.getMovedElements())));
+ }
+ }
+
+ private void computeReparents(Collection<ISequenceNode> sequenceNodesToMove, Map<AbstractNodeEvent, ISequenceEvent> reparents) {
+ // reparent directly moved execution
+ Collection<AbstractNodeEvent> movedExecutions = Lists.newArrayList(Iterables.filter(sequenceNodesToMove, AbstractNodeEvent.class));
+
+ // reparent unmoved executions
+ Collection<AbstractNodeEvent> unmovedExecutions = Lists.newArrayList(Iterables.filter(validator.getDiagram().getAllAbstractNodeEvents(),
+ Predicates.not(Predicates.in(validator.getMovedElements()))));
+
+ for (AbstractNodeEvent execToReparent : Iterables.concat(movedExecutions, unmovedExecutions)) {
+ ISequenceEvent potentialParent = getNewParent(execToReparent, reparents);
+ if (potentialParent instanceof ISequenceNode && !potentialParent.equals(execToReparent.getHierarchicalParentEvent())) {
+ reparents.put(execToReparent, potentialParent);
+ sequenceNodesToMove.remove(execToReparent);
+ }
+ }
+ }
+
+ private Collection<Reconnection> computeReconnections() {
+ Collection<Reconnection> reconnections = Lists.newArrayList();
+ // Reconnect moved and unmoved messages
+ for (Message message : validator.getDiagram().getAllMessages()) {
+
+ // check source change
+ ISequenceNode sourceElement = message.getSourceElement();
+ ISequenceNode newSource = getNewReconnectionEnd(message, sourceElement);
+
+ // check target change
+ ISequenceNode targetElement = message.getTargetElement();
+ ISequenceNode newTarget = targetElement;
+ if (targetElement instanceof ISequenceEvent) {
+ newTarget = getNewReconnectionEnd(message, targetElement);
+ }
+
+ if (!sourceElement.equals(newSource) || !targetElement.equals(newTarget)) {
+ Reconnection rec = new Reconnection(message, newSource, newTarget);
+ reconnections.add(rec);
+ }
+ }
+ return reconnections;
+ }
+
+ private ISequenceEvent getNewParent(AbstractNodeEvent movedExec, Map<AbstractNodeEvent, ISequenceEvent> reparents) {
+ EventFinder newParentFinder = new EventFinder(movedExec.getLifeline().get());
+ newParentFinder.setReparent(true);
+ newParentFinder.setVerticalRangefunction(validator.getRangeFunction());
+ newParentFinder.setEventsToIgnore(Predicates.equalTo((ISequenceEvent) movedExec));
+ newParentFinder.setReparented(reparents);
+ Range futureRange = validator.getRangeFunction().apply(movedExec);
+ Range lookedRange = new Range(futureRange.getLowerBound(), futureRange.getLowerBound());
+
+ if (movedExec instanceof State && movedExec.isLogicallyInstantaneous()) {
+ int mid = futureRange.middleValue();
+ lookedRange = new Range(mid, mid);
+ }
+
+ ISequenceEvent potentialParent = newParentFinder.findMostSpecificEvent(lookedRange);
+ return potentialParent;
+ }
+
+ private ISequenceNode getNewReconnectionEnd(Message message, ISequenceNode actualEnd) {
+ boolean compoundEnds = false;
+ if (message.isReflective() && actualEnd instanceof Execution) {
+ Execution exec = (Execution) actualEnd;
+ compoundEnds = exec.getLinkedMessages().contains(message);
+ }
+
+ boolean bothMoved = false;
+ bothMoved = validator.getMovedElements().contains(message) && validator.getMovedElements().contains(actualEnd);
+
+ if (!compoundEnds && !bothMoved && actualEnd instanceof ISequenceEvent) {
+ EventFinder newEndFinder = new EventFinder(actualEnd.getLifeline().get());
+ newEndFinder.setReconnection(true);
+
+ Range lookedRange = validator.getRangeFunction().apply(message);
+ newEndFinder.setVerticalRangefunction(validator.getRangeFunction());
+
+ ISequenceEvent potentialEnd = newEndFinder.findMostSpecificEvent(lookedRange);
+ if (potentialEnd instanceof ISequenceNode) {
+ return (ISequenceNode) potentialEnd;
+ }
+ }
+ return actualEnd;
+ }
+
+ /**
+ * Wrapper to handle reconnection.
+ *
+ * @author mporhel
+ *
+ */
+ public static class Reconnection {
+ final Message message;
+
+ final ISequenceNode source;
+
+ final ISequenceNode target;
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * message to reconnect.
+ * @param source
+ * source after reconnection.
+ * @param target
+ * target after reconnection.
+ */
+ public Reconnection(Message message, ISequenceNode source, ISequenceNode target) {
+ this.message = message;
+ this.source = source;
+ this.target = target;
+ }
+
+ public Message getMessage() {
+ return message;
+ }
+
+ public ISequenceNode getSource() {
+ return source;
+ }
+
+ public ISequenceNode getTarget() {
+ return target;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleResizableEditPolicy.java
new file mode 100644
index 0000000000..0b8c1fe4bd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleResizableEditPolicy.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+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.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.AlignmentRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.IdentityCommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.graphical.edit.policies.AirResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.MoveViewOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ResizeViewOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.InstanceRoleMoveValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.InstanceRoleResizeValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.tools.api.command.DoNothingCommand;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * A specific AirResizableEditPolicy to manage instance roles move & resize
+ * requests. Constraints :
+ * <ul>
+ * <li>LayoutConstants#LIFELINES_START_X left margin must be always respected</li>
+ * <li>LayoutConstants#LIFELINES_START_Y top margin must be always respected</li>
+ * <li>LayoutConstants#LIFELINES_MIN_X_GAP minimum gap between neighbors
+ * InstanceRoles must be always respected</li>
+ * <li>Resize must not be possible to the top if
+ * LayoutConstants#LIFELINES_START_Y is not respected</li>
+ * <li>Resize must not be possible to the left if
+ * LayoutConstants#LIFELINES_START_X is not respected</li>
+ * <li>Drop a InstanceRole in another index of its initial index in the left to
+ * right ordered list of InstanceRole must not shift InstanceRole at it left but
+ * only shift InstanceRole at it right</li>
+ * </ul>
+ *
+ * @author smonnier, edugueperoux
+ */
+public class InstanceRoleResizableEditPolicy extends AirResizableEditPolicy {
+
+ private static final String INSTANCE_ROLE_MOVE_COMMAND_NAME = "InstanceRole move";
+
+ private static final String INSTANCE_ROLE_RESIZE_COMMAND_NAME = "InstanceRole resize";
+
+ /**
+ * Manage move requests.
+ *
+ * @param request
+ * to move InstanceRoleEditPart's figure
+ *
+ * @return {@link Command} to move InstanceRoleEditPart's figure
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ cancelVerticalMoveDelta(request);
+ Command result = DoNothingCommand.INSTANCE;
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (getHost().getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isMove()) {
+ InstanceRoleMoveValidator validator = new InstanceRoleMoveValidator();
+ List<InstanceRole> instanceRoles = requestQuery.getInstanceRoles();
+ validator.setSequenceElements(instanceRoles);
+
+ result = UnexecutableCommand.INSTANCE;
+ if (validator.isValid(request)) {
+ result = getMoveCommand(validator, requestQuery);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+ cancelVerticalMoveDelta(request);
+ super.showChangeBoundsFeedback(request);
+ }
+
+ private Command getMoveCommand(InstanceRoleMoveValidator validator, RequestQuery requestQuery) {
+ GraphicalEditPart host = (GraphicalEditPart) getHost();
+ TransactionalEditingDomain transactionalEditingDomain = host.getEditingDomain();
+ CompositeTransactionalCommand compositeCommand = new CompositeTransactionalCommand(transactionalEditingDomain, INSTANCE_ROLE_MOVE_COMMAND_NAME);
+ ICommand moveCmds = getMoveViewCommands(transactionalEditingDomain, validator.getMoveDeltas());
+ if (moveCmds != null && moveCmds.canExecute()) {
+ compositeCommand.compose(moveCmds);
+ }
+ postProcessDefaultCommand((InstanceRoleEditPart) getHost(), compositeCommand, requestQuery);
+
+ ICommand solution = compositeCommand;
+ if (!solution.canExecute()) {
+ solution = IdentityCommand.INSTANCE;
+ }
+ return new ICommandProxy(solution);
+ }
+
+ /**
+ * Manage resize requests.
+ *
+ * @param request
+ * to resize InstanceRoleEditPart's figure
+ *
+ * @return {@link Command} to resize InstanceRoleEditPart's figure
+ */
+ @Override
+ protected Command getResizeCommand(ChangeBoundsRequest request) {
+
+ Command result = DoNothingCommand.INSTANCE;
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (getHost().getSelected() == EditPart.SELECTED_PRIMARY && requestQuery.isResize()) {
+ InstanceRoleResizeValidator validator = new InstanceRoleResizeValidator();
+ List<InstanceRole> instanceRoles = requestQuery.getInstanceRoles();
+ validator.setSequenceElements(instanceRoles);
+
+ result = UnexecutableCommand.INSTANCE;
+ if (validator.isValid(request)) {
+ result = getResizeCommand(validator, new RequestQuery(request));
+ }
+ }
+
+ return result;
+ }
+
+ private Command getResizeCommand(InstanceRoleResizeValidator validator, RequestQuery requestQuery) {
+ GraphicalEditPart host = (GraphicalEditPart) getHost();
+ TransactionalEditingDomain transactionalEditingDomain = host.getEditingDomain();
+
+ CompositeTransactionalCommand compositeCommand = new CompositeTransactionalCommand(transactionalEditingDomain, INSTANCE_ROLE_RESIZE_COMMAND_NAME);
+ ICommand moveViewCmd = getMoveViewCommands(transactionalEditingDomain, validator.getMoveDeltas());
+ if (moveViewCmd != null && moveViewCmd.canExecute()) {
+ compositeCommand.compose(moveViewCmd);
+ }
+ ICommand resizeViewCmd = getResizeViewCommands(transactionalEditingDomain, validator.getSizeDeltas());
+ if (resizeViewCmd != null && resizeViewCmd.canExecute()) {
+ compositeCommand.compose(resizeViewCmd);
+ }
+
+ postProcessDefaultCommand((InstanceRoleEditPart) getHost(), compositeCommand, requestQuery);
+
+ ICommand solution = compositeCommand;
+ if (!solution.canExecute()) {
+ solution = IdentityCommand.INSTANCE;
+ }
+ return new ICommandProxy(solution);
+ }
+
+ /**
+ * Get {@link MoveViewOperation} composition from moveDeltas map.
+ *
+ * @param transactionalEditingDomain
+ * TransactionalEditingDomain used to construct the result
+ * ICommand
+ * @param moveDeltas
+ *
+ * @return composition of {@link MoveViewOperation} or null if move/resize
+ * is not needed
+ */
+ private ICommand getMoveViewCommands(TransactionalEditingDomain transactionalEditingDomain, Map<InstanceRole, Point> moveDeltas) {
+ CompositeTransactionalCommand compositeCommand = new CompositeTransactionalCommand(transactionalEditingDomain, "");
+
+ // handle move lost nodes
+ Multimap<InstanceRole, LostMessageEnd> lostNodes = HashMultimap.create();
+
+ InstanceRoleEditPart irep = (InstanceRoleEditPart) getHost();
+ SequenceDiagram diagram = irep.getInstanceRole().getDiagram();
+ for (Message msg : diagram.getAllMessages()) {
+ ISequenceNode sourceElement = msg.getSourceElement();
+ Option<Lifeline> sourceLifeline = sourceElement.getLifeline();
+ ISequenceNode targetElement = msg.getTargetElement();
+ Option<Lifeline> targetLifeline = targetElement.getLifeline();
+ if (sourceLifeline.some() && targetElement instanceof LostMessageEnd) {
+ lostNodes.put(sourceLifeline.get().getInstanceRole(), (LostMessageEnd) targetElement);
+ } else if (sourceElement instanceof LostMessageEnd && targetLifeline.some()) {
+ lostNodes.put(targetLifeline.get().getInstanceRole(), (LostMessageEnd) sourceElement);
+ }
+ }
+
+ // Move commands to shift siblings InstanceRoles
+ for (Entry<InstanceRole, Point> entry : moveDeltas.entrySet()) {
+ Point delta = entry.getValue();
+ if (delta.x != 0 || delta.y != 0) {
+ InstanceRole instanceRole = entry.getKey();
+ addMoveViewCommand(transactionalEditingDomain, compositeCommand, delta, instanceRole);
+
+ // move lost message ends
+ for (LostMessageEnd lme : lostNodes.get(instanceRole)) {
+ addMoveViewCommand(transactionalEditingDomain, compositeCommand, delta, lme);
+ }
+
+ }
+ }
+ return compositeCommand;
+ }
+
+ private void addMoveViewCommand(TransactionalEditingDomain transactionalEditingDomain, CompositeTransactionalCommand compositeCommand, Point delta, ISequenceNode sequenceNode) {
+ IAdaptable adapter = new EObjectAdapter(sequenceNode.getNotationNode());
+ AbstractModelChangeOperation<Void> moveViewOperation = new MoveViewOperation(DiagramUIMessages.SetLocationCommand_Label_Resize, adapter, delta);
+ IUndoableOperation moveCmd = CommandFactory.createICommand(transactionalEditingDomain, moveViewOperation);
+ compositeCommand.add(moveCmd);
+ }
+
+ /**
+ * Get {@link ResizeViewOperation} composition from sizeDeltas map.
+ *
+ * @param transactionalEditingDomain
+ * TransactionalEditingDomain used to construct the result
+ * ICommand
+ *
+ * @return composition of {@link ResizeViewOperation}
+ */
+ private ICommand getResizeViewCommands(TransactionalEditingDomain transactionalEditingDomain, Map<InstanceRole, Dimension> sizeDeltas) {
+ CompositeTransactionalCommand compositeCommand = new CompositeTransactionalCommand(transactionalEditingDomain, "");
+ // Resize Commands
+ for (Entry<InstanceRole, Dimension> entry : sizeDeltas.entrySet()) {
+ Dimension sizeDelta = entry.getValue();
+
+ if (sizeDelta.width != 0 || sizeDelta.height != 0) {
+ InstanceRole instanceRole = entry.getKey();
+ IAdaptable adapter = new EObjectAdapter(instanceRole.getNotationView());
+ AbstractModelChangeOperation<Void> resizeViewOperation = new ResizeViewOperation(DiagramUIMessages.SetLocationCommand_Label_Resize, adapter, sizeDelta);
+ IUndoableOperation resizeCmd = CommandFactory.createICommand(transactionalEditingDomain, resizeViewOperation);
+ compositeCommand.add(resizeCmd);
+ }
+ }
+ if (!compositeCommand.canExecute()) {
+ return null;
+ }
+ return compositeCommand;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAutoSizeCommand(Request request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAlignCommand(AlignmentRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * Cancel vertical changes of the given request.
+ *
+ * @param request
+ * a request.
+ */
+ protected void cancelVerticalMoveDelta(ChangeBoundsRequest request) {
+ if (request == null) {
+ return;
+ }
+
+ RequestQuery query = new RequestQuery(request);
+ if (query.isMove()) {
+ Point moveDelta = request.getMoveDelta().getCopy();
+ if (moveDelta != null) {
+ request.setMoveDelta(new Point(moveDelta.x, 0));
+ }
+ }
+ }
+
+ private void postProcessDefaultCommand(InstanceRoleEditPart self, CompositeTransactionalCommand command, RequestQuery requestQuery) {
+ if (command != null && command.canExecute()) {
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(command, self);
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(command, self);
+ if (requestQuery.isMultiSelectionOperation()) {
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(command, self.getInstanceRole(), requestQuery.getInstanceRoles());
+ } else {
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(command, self.getInstanceRole());
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleSiriusGraphicalNodeEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleSiriusGraphicalNodeEditPolicy.java
new file mode 100644
index 0000000000..3ea2b48334
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InstanceRoleSiriusGraphicalNodeEditPolicy.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+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.gef.editparts.AbstractGraphicalEditPart;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gef.requests.CreateConnectionRequest;
+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.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.description.tool.EdgeCreationDescription;
+import org.eclipse.sirius.diagram.business.internal.view.EdgeLayoutData;
+import org.eclipse.sirius.diagram.graphical.edit.policies.SiriusGraphicalNodeEditPolicy;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNode2EditPart;
+import org.eclipse.sirius.diagram.internal.view.factories.ViewLocationHint;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.EndOfLifeMoveOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.ShiftDirectSubExecutionsOperation;
+import org.eclipse.sirius.diagram.sequence.description.tool.MessageCreationTool;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ShiftDescendantMessagesOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.CreateMessageCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+
+/**
+ * {@link SiriusGraphicalNodeEditPolicy} specific to sequence to manage
+ * creation of message targeting InstanceRole (create & destroy messages).
+ *
+ * @author edugueperoux
+ */
+public class InstanceRoleSiriusGraphicalNodeEditPolicy extends SiriusGraphicalNodeEditPolicy {
+
+ /**
+ * overriden to handle Ymove of InstanceRoles when connecting a
+ * "create message".
+ *
+ * @param request
+ * the request to create a new connection targeting an
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart}
+ * @return a command that wrap the Y move
+ */
+ @Override
+ protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
+ Command result = UnexecutableCommand.INSTANCE;
+
+ TransactionalEditingDomain domain = ((IGraphicalEditPart) getHost()).getEditingDomain();
+
+ InstanceRoleEditPart host = (InstanceRoleEditPart) getHost();
+ ISequenceElement sequenceElement = host.getInstanceRole();
+ SequenceDiagram sequenceDiagram = sequenceElement.getDiagram();
+
+ RequestQuery requestQuery = new RequestQuery(request);
+
+ if (requestQuery.isCreateMessageCreation()) {
+ CreateMessageCreationValidator validator = new CreateMessageCreationValidator();
+
+ EditPart sourceEditPart = request.getSourceEditPart();
+ EditPart targetEditPart = request.getTargetEditPart();
+
+ Option<Lifeline> lifelineSource = ISequenceElementAccessor.getISequenceElement((View) sourceEditPart.getModel()).get().getLifeline();
+ Option<Lifeline> lifelineTarget = ISequenceElementAccessor.getISequenceElement((View) targetEditPart.getModel()).get().getLifeline();
+
+ InstanceRole instanceRoleSource = lifelineSource.get().getInstanceRole();
+ InstanceRole instanceRoleTarget = lifelineTarget.get().getInstanceRole();
+
+ validator.setSource(instanceRoleSource);
+ validator.setTarget(instanceRoleTarget);
+
+ Point firstClickLocation = SequenceEditPartsOperations.getConnectionSourceLocation(request, host);
+ Point secondClickLocation = SequenceEditPartsOperations.getConnectionTargetLocation(request, host);
+
+ // Creation message will be horizontal.
+ if (!ExecutionSemanticEditPolicy.isCombinedFragmentTitleRangeEdgeCreation(sequenceElement, sequenceDiagram, firstClickLocation, firstClickLocation)) {
+
+ validator.setFirstClickLocation(firstClickLocation);
+ validator.setSecondClickLocation(secondClickLocation);
+
+ if (validator.isValid(request)) {
+ result = super.getConnectionCompleteCommand(request);
+ }
+ }
+ } else {
+
+ // OLD code
+ // TODO EDU : refactor this following with validators
+ result = super.getConnectionCompleteCommand(request);
+ if (result != null && result.canExecute() && validateIsConnectingCreateMessage(request)) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(domain, "Move down lifeline/ add create participant message");
+ Point sourceLocation = ((Point) ViewLocationHint.getInstance().getData(org.eclipse.gef.RequestConstants.REQ_CONNECTION_START)).getCopy();
+ final LifelineEditPart lep = EditPartsHelper.getAllLifelines((IGraphicalEditPart) getHost()).get(0);
+
+ if (((AbstractGraphicalEditPart) getHost()).getTargetConnections().isEmpty() && validateIsNotCreateMessageToSelf(request) && validateNoEventBeforeCreate(sourceLocation, lep)
+ && validateNotCreatingMessageInDifferentOperands(request, sourceLocation)) {
+
+ // Create a ChangeBoundsRequest to move down the targeted
+ // InstanceRoleEditPart to the Y position of connection
+ // source
+ ChangeBoundsRequest changeBoundsRequest = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ Rectangle bounds = ((AbstractGraphicalEditPart) getHost()).getFigure().getBounds();
+ Point scrollSize = GraphicalHelper.getScrollSize((IGraphicalEditPart) getHost());
+ int yMoveNeeded = sourceLocation.y - bounds.y - bounds.height / 2 + scrollSize.y;
+
+ changeBoundsRequest.setMoveDelta(new Point(0, yMoveNeeded));
+ // add a specific extended data to enable vertical move of
+ // an
+ // InstanceRoleEditPart
+ changeBoundsRequest.setConstrainedMove(true);
+ changeBoundsRequest.setEditParts(getHost());
+ ctc.compose(new CommandProxy(getHost().getCommand(changeBoundsRequest)));
+ ctc.compose(new CommandProxy(result));
+
+ /*
+ * These additional commands adjust the positions of the
+ * executions and messages on the lifeline so that visually
+ * they do not move. They are dual to the commands we add
+ * when moving a normal execution, as in that case we want
+ * all the executions and messages it contains to move
+ * along.
+ */
+ final int deltaY = changeBoundsRequest.getMoveDelta().y;
+
+ // Avoid EndOfLife Move
+ Lifeline lifeline = (Lifeline) lep.getISequenceEvent();
+ ctc.compose(CommandFactory.createICommand(domain, new EndOfLifeMoveOperation(lifeline, -deltaY)));
+ ctc.compose(CommandFactory.createICommand(domain, new ShiftDirectSubExecutionsOperation(lep.getISequenceEvent(), -deltaY)));
+ ctc.compose(CommandFactory.createICommand(domain, new ShiftDescendantMessagesOperation(lep.getISequenceEvent(), deltaY, true, false, true)));
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(ctc, (IGraphicalEditPart) getHost());
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, (IGraphicalEditPart) getHost());
+
+ } else {
+ result = UnexecutableCommand.INSTANCE;
+ }
+ result = new ICommandProxy(ctc);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * validate if the request will create a "create message".
+ *
+ * @param request
+ * the request to create a new connection targeting an
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart}
+ * @return if the request will create a "create message"
+ */
+ private boolean validateIsConnectingCreateMessage(CreateConnectionRequest request) {
+ // validate request type
+ boolean result = org.eclipse.gef.RequestConstants.REQ_CONNECTION_END.equals(request.getType()) && request.getNewObject() instanceof MessageCreationTool;
+ // validate request connection ends
+ result = result && getHost().equals(request.getTargetEditPart()) && request.getSourceEditPart() instanceof DNode2EditPart;
+ return result;
+ }
+
+ /**
+ * validate the request will not create a "create message" to self.
+ *
+ * @param request
+ * the request to create a "create message".
+ * @return the validation that this request will not create a
+ * "create message" to self.
+ */
+ private boolean validateIsNotCreateMessageToSelf(CreateConnectionRequest request) {
+ // validate request does not add a create message to self
+ return EditPartsHelper.findParentLifeline((IGraphicalEditPart) request.getSourceEditPart()).getParent() != request.getTargetEditPart();
+ }
+
+ /**
+ * Validates that a message is not created between two elements that are not
+ * in the same operand.
+ *
+ * @param request
+ * current create connection request
+ * @param location
+ * location of target
+ * @return the validation that a message is not created between two elements
+ * that are not in the same operand.
+ */
+ private boolean validateNotCreatingMessageInDifferentOperands(CreateConnectionRequest request, Point location) {
+ boolean result = false;
+ if (getHost() instanceof InstanceRoleEditPart && request.getSourceEditPart() instanceof ISequenceEventEditPart) {
+ GraphicalHelper.screen2logical(location, (InstanceRoleEditPart) getHost());
+
+ InstanceRoleEditPart targetEditPart = (InstanceRoleEditPart) getHost();
+ Option<Operand> targetParentOperand;
+ if (targetEditPart.getInstanceRole().getLifeline().some()) {
+ targetParentOperand = targetEditPart.getInstanceRole().getLifeline().get().getParentOperand(location.y);
+ } else {
+ targetParentOperand = Options.newNone();
+ }
+
+ ISequenceEventEditPart sourceEditPart = (ISequenceEventEditPart) request.getSourceEditPart();
+ Option<Operand> sourceParentOperand;
+ if (sourceEditPart.getISequenceEvent() instanceof Lifeline) {
+ sourceParentOperand = ((Lifeline) sourceEditPart.getISequenceEvent()).getParentOperand(location.y);
+ } else {
+ sourceParentOperand = sourceEditPart.getISequenceEvent().getParentOperand();
+ }
+ if (targetParentOperand.some()) {
+ // if the target is in an operand, the source has to be in the
+ // same operand.
+ result = sourceParentOperand.some() && targetParentOperand.get().equals(sourceParentOperand.get());
+ } else {
+ // if the target is not in an operand, the source has to be in
+ // no operand as well.
+ result = !sourceParentOperand.some();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validates that there is no message on the targeted
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart}
+ * before sourceLocation Y position. There can not be any message before
+ * creation.
+ *
+ * @param sourceLocation
+ * location where the create message has its source
+ * @param lep
+ * @return if there is no message on the targeted
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart}
+ * before sourceLocation
+ */
+ private boolean validateNoEventBeforeCreate(final Point sourceLocation, LifelineEditPart lep) {
+ ISequenceEvent lifeline = lep.getISequenceEvent();
+ int firstEventInTargetInstanceRole = lifeline.getVerticalRange().getUpperBound();
+
+ // Filter the combined fragment that contain source location to be able
+ // to add a create message
+ Predicate<ISequenceEvent> notParentCombinedFragment = new Predicate<ISequenceEvent>() {
+
+ public boolean apply(ISequenceEvent input) {
+ if (input instanceof CombinedFragment) {
+ CombinedFragment combinedFragment = (CombinedFragment) input;
+ return !combinedFragment.getVerticalRange().includes(sourceLocation.y);
+ }
+ return true;
+ }
+ };
+
+ for (ISequenceEvent ise : Iterables.filter(lifeline.getSubEvents(), notParentCombinedFragment)) {
+ firstEventInTargetInstanceRole = Math.min(firstEventInTargetInstanceRole, ise.getVerticalRange().getLowerBound());
+ }
+
+ return sourceLocation.y < firstEventInTargetInstanceRole;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.graphical.edit.policies.SiriusGraphicalNodeEditPolicy#buildCreateEdgeCommand(org.eclipse.gef.requests.CreateConnectionRequest,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.description.tool.EdgeCreationDescription,
+ * org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider,
+ * org.eclipse.sirius.diagram.business.internal.view.EdgeLayoutData)
+ */
+ @Override
+ protected Command buildCreateEdgeCommand(CreateConnectionRequest request, EdgeTarget source, EdgeTarget target, EdgeCreationDescription edgeCreationDescription,
+ IDiagramCommandFactoryProvider cmdFactoryProvider, EdgeLayoutData edgeLayoutData) {
+ CompoundCommand result = new CompoundCommand();
+ SequenceEditPartsOperations.appendFullRefresh((IGraphicalEditPart) getHost(), result);
+ addStoreLayoutDataCommand(result, edgeLayoutData);
+ SequenceEditPartsOperations.buildCreateEdgeCommand((IGraphicalEditPart) getHost(), result, request, source, target, edgeCreationDescription, cmdFactoryProvider);
+ SequenceEditPartsOperations.appendFullRefresh((IGraphicalEditPart) getHost(), result);
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InteractionUseResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InteractionUseResizableEditPolicy.java
new file mode 100644
index 0000000000..60d028da4f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/InteractionUseResizableEditPolicy.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.VerticalSpaceExpansion;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InteractionUseEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractInteractionFrameValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.InteractionUseMoveValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * A specific AirResizableEditPolicy to manage interaction use roles move &
+ * resize requests.
+ *
+ * @author mporhel
+ */
+public class InteractionUseResizableEditPolicy extends AbstractFrameResizableEditPolicy {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ cancelHorizontalDelta(request);
+ Command result = super.getMoveCommand(request);
+
+ InteractionUseEditPart iuep = (InteractionUseEditPart) getHost();
+ InteractionUseMoveValidator validator = new InteractionUseMoveValidator((InteractionUse) iuep.getISequenceEvent(), new RequestQuery(request));
+
+ if (validator.isValid()) {
+ // TODO Implement MoveInteractionUseCommand
+ } else {
+ result = UnexecutableCommand.INSTANCE;
+ }
+
+ result = postProcessDefaultCommand(iuep, request, result, validator);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getResizeCommand(ChangeBoundsRequest request) {
+ Command result = super.getResizeCommand(request);
+
+ InteractionUseEditPart iuep = (InteractionUseEditPart) getHost();
+ AbstractInteractionFrameValidator validator = AbstractInteractionFrameValidator.getOrCreateResizeValidator(request, (InteractionUse) iuep.getISequenceEvent());
+
+ if (validator.isValid()) {
+ // TODO Implement ResizeInteractionUseCommand
+ } else {
+ result = UnexecutableCommand.INSTANCE;
+ }
+
+ result = postProcessDefaultCommand(iuep, request, result, validator);
+ return result;
+ }
+
+ private Command postProcessDefaultCommand(InteractionUseEditPart self, ChangeBoundsRequest request, Command defaultCommand, AbstractInteractionFrameValidator validator) {
+ Command result = defaultCommand;
+
+ if (result != null && result.canExecute()) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(self.getEditingDomain(), "Interaction Use Move Composite Command");
+ ctc.setLabel(String.valueOf(defaultCommand.getLabel()));
+ ctc.compose(new CommandProxy(defaultCommand));
+
+ Range expansionZone = validator.getExpansionZone();
+ if (expansionZone != null && !expansionZone.isEmpty()) {
+ ISequenceEvent iSequenceEvent = self.getISequenceEvent();
+ SequenceDiagram diagram = iSequenceEvent.getDiagram();
+ Collection<ISequenceEvent> eventToIgnore = Collections.singletonList(iSequenceEvent);
+ ICommand autoExpand = CommandFactory.createICommand(self.getEditingDomain(), new VerticalSpaceExpansion(diagram, expansionZone, 0, eventToIgnore));
+ ctc.compose(autoExpand);
+ }
+
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, self.getISequenceEvent());
+ result = new ICommandProxy(ctc);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceEventEditPart> getChildrenToFeedBack(ChangeBoundsRequest request) {
+ return Lists.newArrayList();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/LostMessageEndSelectionPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/LostMessageEndSelectionPolicy.java
new file mode 100644
index 0000000000..b552cf103a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/LostMessageEndSelectionPolicy.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.List;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.AlignmentRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.internal.requests.ChangeBoundsDeferredRequest;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.graphical.edit.policies.AirResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LostMessageEndEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+
+/**
+ * This policy controls the moves of {@link LostMessageEndEditPart}s.
+ *
+ * @author mporhel
+ */
+public class LostMessageEndSelectionPolicy extends AirResizableEditPolicy {
+
+ private static List<Integer> handledAlignments = Lists.newArrayList();
+ {
+ handledAlignments.add(PositionConstants.LEFT);
+ handledAlignments.add(PositionConstants.CENTER);
+ handledAlignments.add(PositionConstants.RIGHT);
+ }
+
+ /**
+ * Overridden to validate the host type.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void setHost(EditPart host) {
+ Preconditions.checkArgument(host instanceof LostMessageEndEditPart);
+ super.setHost(host);
+ }
+
+ /**
+ * Convenience method to return the host part with the correct type.
+ *
+ * @return returns the host of this policy, with the appropriate type.
+ */
+ protected LostMessageEndEditPart getLostMessageEnd() {
+ return (LostMessageEndEditPart) getHost();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAlignCommand(AlignmentRequest request) {
+ Command result = UnexecutableCommand.INSTANCE;
+
+ if (handledAlignments.contains(request.getAlignment())) {
+ result = super.getAlignCommand(request);
+ }
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ cancelVerticalMoveDelta(request);
+ return super.getMoveCommand(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveDeferredCommand(ChangeBoundsDeferredRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+ cancelVerticalMoveDelta(request);
+ super.showChangeBoundsFeedback(request);
+ }
+
+ /**
+ * Cancel vertical changes of the given request.
+ *
+ * @param request
+ * a request.
+ */
+ protected void cancelVerticalMoveDelta(ChangeBoundsRequest request) {
+ if (request == null) {
+ return;
+ }
+
+ RequestQuery query = new RequestQuery(request);
+ if (query.isMove()) {
+ Point moveDelta = request.getMoveDelta().getCopy();
+ if (moveDelta != null) {
+ request.setMoveDelta(new Point(moveDelta.x, 0));
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ObservationPointSelectionPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ObservationPointSelectionPolicy.java
new file mode 100644
index 0000000000..883f82306e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/ObservationPointSelectionPolicy.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.AlignmentRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.internal.requests.ChangeBoundsDeferredRequest;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.graphical.edit.policies.AirResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ObservationPointEditPart;
+
+/**
+ * This policy controls the moves of {@link ObservationPointEditPart}s.
+ *
+ * @author mporhel
+ */
+public class ObservationPointSelectionPolicy extends AirResizableEditPolicy {
+
+ /**
+ * Overridden to validate the host type.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public void setHost(EditPart host) {
+ Preconditions.checkArgument(host instanceof ObservationPointEditPart);
+ super.setHost(host);
+ }
+
+ /**
+ * Convenience method to return the host part with the correct type.
+ *
+ * @return returns the host of this policy, with the appropriate type.
+ */
+ protected ObservationPointEditPart getObservationPoint() {
+ return (ObservationPointEditPart) getHost();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAlignCommand(AlignmentRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveDeferredCommand(ChangeBoundsDeferredRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java
new file mode 100644
index 0000000000..7a19ca2074
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/OperandResizableEditPolicy.java
@@ -0,0 +1,337 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.draw2d.PositionConstants;
+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.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gef.requests.AlignmentRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+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.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.Size;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.diagram.graphical.edit.policies.AirResizableEditPolicy;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.OperandEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.OperandResizeValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * A specific AirResizableEditPolicy to operand roles move & resize requests.
+ *
+ * @author smonnier
+ */
+public class OperandResizableEditPolicy extends AirResizableEditPolicy {
+
+ private static final String RESIZE = "Resize";
+
+ /**
+ * Constructor.
+ */
+ public OperandResizableEditPolicy() {
+ super();
+ setResizeDirections(PositionConstants.NORTH_SOUTH);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getMoveCommand(ChangeBoundsRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getResizeCommand(ChangeBoundsRequest request) {
+ cancelHorizontalDelta(request);
+
+ OperandEditPart oep = (OperandEditPart) getHost();
+ OperandResizeValidator operandResizeValidator = new OperandResizeValidator((Operand) oep.getISequenceEvent(), new RequestQuery(request));
+ operandResizeValidator.validate();
+
+ Command result;
+ if (operandResizeValidator.isValid()) {
+ result = getResizeCustomCommand(oep, request);
+ } else {
+ result = UnexecutableCommand.INSTANCE;
+ }
+ return result;
+ }
+
+ private static Point getPositionFromView(IGraphicalEditPart part) {
+ final Point position = new Point();
+ if (part.getNotationView() instanceof Node && ((Node) part.getNotationView()).getLayoutConstraint() instanceof Location) {
+ final Location location = (Location) ((Node) part.getNotationView()).getLayoutConstraint();
+ position.x = location.getX();
+ position.y = location.getY();
+ }
+ return position;
+ }
+
+ private static Dimension getDimensionFromView(IGraphicalEditPart part) {
+ final Dimension dimension = new Dimension();
+ if (part.getNotationView() instanceof Node && ((Node) part.getNotationView()).getLayoutConstraint() instanceof Size) {
+ final Size size = (Size) ((Node) part.getNotationView()).getLayoutConstraint();
+ dimension.width = size.getWidth();
+ dimension.height = size.getHeight();
+ }
+ return dimension;
+ }
+
+ /**
+ * Returns the command to resize a bordered node.
+ *
+ * @param part
+ * the edit part corresponding to the bordered node.
+ * @param request
+ * the request for a resize.
+ * @return the command to resize a bordered node.
+ */
+ public static AbstractTransactionalCommand getResizeBorderItemTCommand(IGraphicalEditPart part, ChangeBoundsRequest request) {
+ final EObject semantic = part.resolveSemanticElement();
+ if (semantic instanceof DNodeContainer) {
+ final double zoom = ((ZoomManager) part.getViewer().getProperty(ZoomManager.class.toString())).getZoom();
+ final Dimension dimension = OperandResizableEditPolicy.getDimensionFromView(part);
+ final Point position = OperandResizableEditPolicy.getPositionFromView(part);
+ dimension.height += request.getSizeDelta().height / zoom;
+ switch (request.getResizeDirection()) {
+ case PositionConstants.NORTH:
+ case PositionConstants.NORTH_WEST:
+ case PositionConstants.NORTH_EAST:
+ position.y -= request.getSizeDelta().height / zoom;
+ break;
+ default:
+ break;
+ }
+ return new SetBoundsCommand(part.getEditingDomain(), RESIZE, new EObjectAdapter(part.getNotationView()), new Rectangle(position, dimension));
+ }
+ return null;
+ }
+
+ private Command getResizeCustomCommand(OperandEditPart self, ChangeBoundsRequest request) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(self.getEditingDomain(), "Operand Resize Composite Command");
+ ctc.add(OperandResizableEditPolicy.getResizeBorderItemTCommand(self, request));
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(self.getNotationView());
+ if (operandOption.some()) {
+ Operand operand = operandOption.get();
+ int operandIndex = operand.getIndex();
+ if (request.getResizeDirection() == PositionConstants.NORTH) {
+ // Resizing the operand from north face must resize the
+ // previous operand
+ OperandEditPart previousOperandEditPart = getPreviousOperandEditPart(operandIndex);
+ if (previousOperandEditPart == null && self.getSelected() != EditPart.SELECTED_NONE) {
+ // There is no previous operand, resize from north face
+ // is forbidden
+ ctc.add(new CommandProxy(UnexecutableCommand.INSTANCE));
+ } else if (previousOperandEditPart != null) {
+ // We apply the inverse resize to the previous operand
+ Option<Operand> previousOperandOption = ISequenceElementAccessor.getOperand(previousOperandEditPart.getNotationView());
+ Operand previousOperand = previousOperandOption.get();
+ Range previousOperandVerticalRange = previousOperand.getVerticalRange();
+ Range combinedFragmentVerticalRange = previousOperand.getCombinedFragment().getVerticalRange();
+ int delta = previousOperandVerticalRange.getLowerBound() - combinedFragmentVerticalRange.getLowerBound();
+ Point newLocation = new Point(0, delta);
+ Dimension newDimension = new Dimension(previousOperand.getBounds().width, previousOperandVerticalRange.width() - request.getSizeDelta().height);
+ ctc.add(createOperandSetBoundsCommand(previousOperandEditPart, newLocation, newDimension));
+ postProcessDefaultCommand(ctc, self);
+ }
+ } else if (request.getResizeDirection() == PositionConstants.SOUTH) {
+ OperandEditPart followingOperandEditPart = getFollowingOperandEditPart(operandIndex);
+ if (followingOperandEditPart == null && self.getSelected() != EditPart.SELECTED_NONE) {
+ // There is no following operand, resize from south face
+ // is forbidden
+ ctc.add(new CommandProxy(UnexecutableCommand.INSTANCE));
+ } else if (followingOperandEditPart != null) {
+ // We apply the inverse resize to the following operand
+ Option<Operand> followingOperandOption = ISequenceElementAccessor.getOperand(followingOperandEditPart.getNotationView());
+ Operand followingOperand = followingOperandOption.get();
+ Range followingOperandVerticalRange = followingOperand.getVerticalRange();
+ Range combinedFragmentVerticalRange = followingOperand.getCombinedFragment().getVerticalRange();
+ int delta = followingOperandVerticalRange.getLowerBound() - combinedFragmentVerticalRange.getLowerBound();
+ Point newLocation = new Point(0, delta + request.getSizeDelta().height);
+ Dimension newDimension = new Dimension(followingOperand.getBounds().width, followingOperandVerticalRange.width() - request.getSizeDelta().height);
+ ctc.add(createOperandSetBoundsCommand(followingOperandEditPart, newLocation, newDimension));
+ postProcessDefaultCommand(ctc, self);
+ }
+ }
+ }
+ return new ICommandProxy(ctc);
+ }
+
+ /**
+ * Refresh ordering.
+ *
+ * @param ctc
+ * the current command create on operand resize
+ * @param self
+ * the {@link OperandEditPart} that is resizing
+ */
+ private void postProcessDefaultCommand(CompositeTransactionalCommand ctc, OperandEditPart self) {
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addRefreshSemanticOrderingCommand(ctc, self);
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, self.getISequenceEvent());
+ }
+
+ /**
+ * Creates the {@link SetBoundsCommand} to resize an operand.
+ *
+ * @param part
+ * the {@link OperandEditPart}
+ * @param location
+ * the new location of the operand
+ * @param dimension
+ * the new dimension of the operand
+ * @return a command to resize an operand
+ */
+ private AbstractTransactionalCommand createOperandSetBoundsCommand(IGraphicalEditPart part, Point location, Dimension dimension) {
+ return new SetBoundsCommand(part.getEditingDomain(), RESIZE, new EObjectAdapter(part.getNotationView()), new Rectangle(location, dimension));
+ }
+
+ /**
+ * Finds the previous {@link OperandEditPart} of the current
+ * {@link OperandEditPart} identified by the index currentOperandIndex.
+ *
+ * @param currentOperandIndex
+ * the index of the current {@link OperandEditPart}
+ * @return the previous {@link OperandEditPart}
+ */
+ private OperandEditPart getPreviousOperandEditPart(int currentOperandIndex) {
+ for (OperandEditPart operandEditPart : Iterables.filter(getHost().getParent().getChildren(), OperandEditPart.class)) {
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(operandEditPart.getNotationView());
+ if (operandOption.some()) {
+ Operand operand = operandOption.get();
+ int operandIndex = operand.getIndex();
+ if (operandIndex == currentOperandIndex - 1) {
+ return operandEditPart;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds the following {@link OperandEditPart} of the current
+ * {@link OperandEditPart} identified by the index currentOperandIndex.
+ *
+ * @param currentOperandIndex
+ * the index of the current {@link OperandEditPart}
+ * @return the following {@link OperandEditPart}
+ */
+ private OperandEditPart getFollowingOperandEditPart(int currentOperandIndex) {
+ for (OperandEditPart operandEditPart : Iterables.filter(getHost().getParent().getChildren(), OperandEditPart.class)) {
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(operandEditPart.getNotationView());
+ if (operandOption.some()) {
+ Operand operand = operandOption.get();
+ int operandIndex = operand.getIndex();
+ if (operandIndex == currentOperandIndex + 1) {
+ return operandEditPart;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void cancelHorizontalDelta(ChangeBoundsRequest request) {
+ if (request == null) {
+ return;
+ }
+
+ Point moveDelta = request.getMoveDelta();
+ if (moveDelta != null) {
+ request.setMoveDelta(new Point(0, moveDelta.y));
+ }
+
+ Dimension sizeDelta = request.getSizeDelta();
+ if (sizeDelta != null) {
+ request.setSizeDelta(new Dimension(0, sizeDelta.height));
+ }
+ }
+
+ private void cancelVerticalDelta(ChangeBoundsRequest request) {
+ if (request == null) {
+ return;
+ }
+
+ Point moveDelta = request.getMoveDelta();
+ if (moveDelta != null) {
+ request.setMoveDelta(new Point(moveDelta.x, 0));
+ }
+
+ Dimension sizeDelta = request.getSizeDelta();
+ if (sizeDelta != null) {
+ request.setSizeDelta(new Dimension(sizeDelta.width, 0));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAutoSizeCommand(Request request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getAlignCommand(AlignmentRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}.
+ */
+ @Override
+ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+ cancelHorizontalDelta(request);
+ RequestQuery query = new RequestQuery(request);
+ if (query.isMove()) {
+ cancelVerticalDelta(request);
+ }
+ super.showChangeBoundsFeedback(request);
+ }
+
+ /**
+ * {@inheritDoc}.
+ *
+ * Overridden to cancel feedback move because operand move is forbidden.
+ */
+ @Override
+ public void showSourceFeedback(Request request) {
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java
new file mode 100644
index 0000000000..db7c257210
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java
@@ -0,0 +1,333 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.LayerConstants;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.editparts.LayerManager;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+import org.eclipse.sirius.description.tool.NodeCreationDescription;
+import org.eclipse.sirius.diagram.graphical.edit.policies.ContainerCreationEditPolicy;
+import org.eclipse.sirius.diagram.graphical.edit.policies.CreationUtil;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.VerticalSpaceExpansion;
+import org.eclipse.sirius.diagram.sequence.description.tool.CombinedFragmentCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InstanceRoleCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InteractionUseCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ObservationPointCreationTool;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command.SequenceDelegatingCommandFactory;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.FrameCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.CreateRequestQuery;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.command.DoNothingCommand;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+
+/**
+ * An extension of the standard Sirius ContainerCreationEditPolicy which
+ * knows how to handle the specific tools use to create frames (i.e. Interaction
+ * Uses and Combined Fragments).
+ *
+ * @author pcdavid
+ */
+public class SequenceContainerCreationPolicy extends ContainerCreationEditPolicy {
+
+ /**
+ * Additional figures for feedback.
+ */
+ protected Collection<Figure> guides = Lists.newArrayList();
+
+ @Override
+ protected Command getCreateNodeOnDiagramCommand(CreateRequest request, NodeCreationDescription tool, DDiagram diagram) {
+ Command result;
+ if (tool instanceof ObservationPointCreationTool && diagram instanceof SequenceDDiagram) {
+ SequenceDDiagram diag = (SequenceDDiagram) diagram;
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+
+ EventEnd startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(diag, location.y);
+ EventEnd finishingEndEndPredecessor = startingEndPredecessor;
+ if (request.getSize() != null) {
+ Dimension size = request.getSize().getCopy();
+ GraphicalHelper.screen2logical(size, (IGraphicalEditPart) getHost());
+ finishingEndEndPredecessor = SequenceGraphicalHelper.getEndBefore(diag, location.y + size.height);
+ }
+
+ CreationUtil creationUtil = new CreationUtil(request, getDiagramCommandFactory(startingEndPredecessor, finishingEndEndPredecessor, location), getRealLocation(request), request.getSize(),
+ getHost());
+ result = creationUtil.getNodeCreationCommand(diagram, tool);
+ } else if (tool instanceof InstanceRoleCreationTool && diagram instanceof SequenceDDiagram) {
+ SequenceDDiagram diag = (SequenceDDiagram) diagram;
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+
+ EObject predecessor = SequenceGraphicalHelper.getInstanceRoleBefore(diag, location.x);
+ CreationUtil creationUtil = new CreationUtil(request, getDiagramCommandFactory(predecessor, location), getRealLocation(request), request.getSize(), getHost());
+ result = creationUtil.getNodeCreationCommand(diagram, tool);
+ } else {
+ result = super.getCreateNodeOnDiagramCommand(request, tool, diagram);
+ }
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getCreateContainerOnDiagramCommand(CreateRequest request, ContainerCreationDescription ccdTool, DDiagram diagram) {
+ Command result;
+
+ boolean frameCreationTool = ccdTool instanceof InteractionUseCreationTool || ccdTool instanceof CombinedFragmentCreationTool;
+ if (frameCreationTool && getHost() instanceof SequenceDiagramEditPart && diagram instanceof SequenceDDiagram) {
+ SequenceDiagramEditPart sdep = (SequenceDiagramEditPart) getHost();
+ TransactionalEditingDomain domain = sdep.getEditingDomain();
+ Diagram gmfDiagram = sdep.getDiagramView();
+ SequenceDiagram sequenceDiagram = ISequenceElementAccessor.getSequenceDiagram(gmfDiagram).get();
+ FrameCreationValidator creationValidator = FrameCreationValidator.getOrCreateValidator(sequenceDiagram, ccdTool, new CreateRequestQuery(request, sdep));
+
+ if (creationValidator.isValid()) {
+ EventEnd startingEndPredecessor = creationValidator.getStartingEndPredecessor();
+ EventEnd finishingEndPredecessor = creationValidator.getFinishingEndPredecessor();
+ List<EObject> coverage = creationValidator.getCoverage();
+ Range expansionZone = creationValidator.getExpansionZone();
+
+ CreationUtil creationUtil = new CreationUtil(request, getDiagramCommandFactory(startingEndPredecessor, finishingEndPredecessor, coverage, getCreationRange(request)),
+ getRealLocation(request), getRealSize(ccdTool, request), getHost());
+ result = creationUtil.getContainerCreationDescription(diagram, ccdTool);
+
+ // Add a vertical expansion command if we do inclusion
+ if (expansionZone != null && !expansionZone.isEmpty() && result != null && result.canExecute()) {
+ // Shift the element to not include int the range of the
+ // AbstractFrame to create
+ VerticalSpaceExpansion verticalSpaceExpansion = new VerticalSpaceExpansion(sequenceDiagram, expansionZone, 0, Collections.<ISequenceEvent> emptyList());
+ ICommand expandSubEventsCmd = CommandFactory.createICommand(domain, verticalSpaceExpansion);
+
+ result = new ICommandProxy(expandSubEventsCmd).chain(result);
+ }
+ } else {
+ result = creationValidator.getCoverage().isEmpty() ? DoNothingCommand.INSTANCE : UnexecutableCommand.INSTANCE;
+ }
+ } else {
+ result = super.getCreateContainerOnDiagramCommand(request, ccdTool, diagram);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to show the feedback of the expansion zone for
+ * InteractionUse/CombinedFragment creation when there is inclusion of
+ * existing sequence events in its creation range and vertical space
+ * expansion is needed for some sequence events.
+ *
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void showTargetFeedback(Request request) {
+ eraseTargetFeedback(request);
+ if (request instanceof CreateRequest && this.getHost() instanceof SequenceDiagramEditPart) {
+ SequenceDiagramEditPart sdep = (SequenceDiagramEditPart) getHost();
+ CreateRequest createRequest = (CreateRequest) request;
+ Option<ISequenceElement> seqDiag = ISequenceElementAccessor.getISequenceElement((View) this.getHost().getModel());
+ AbstractToolDescription tool = getTool(createRequest);
+ if (seqDiag.some() && seqDiag.get() instanceof SequenceDiagram && tool instanceof InteractionUseCreationTool || tool instanceof CombinedFragmentCreationTool) {
+ FrameCreationValidator validator = FrameCreationValidator.getOrCreateValidator((SequenceDiagram) seqDiag.get(), (ContainerCreationDescription) tool, new CreateRequestQuery(
+ createRequest, sdep));
+ if (validator != null) {
+ SequenceInteractionFeedBackBuilder feedBackBuilder = new SequenceInteractionFeedBackBuilder(validator, getFeedbackLayer(), (IGraphicalEditPart) getHost());
+ for (Figure fig : feedBackBuilder.buildFeedBack()) {
+ addFeedback(fig);
+ guides.add(fig);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Overridden to erase feedback for AbstractFrame creation request.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void eraseTargetFeedback(Request request) {
+ removeFeedBackOnGuides();
+ }
+
+ private void removeFeedBackOnGuides() {
+ if (guides != null && !guides.isEmpty()) {
+ for (Figure hGuide : guides) {
+ removeFeedback(hGuide);
+ }
+ guides.clear();
+ }
+ }
+
+ /**
+ * Add a IFigure to the feedbackLayer.
+ *
+ * @param figure
+ * the feedback figure to add
+ */
+ protected void addFeedback(IFigure figure) {
+ getFeedbackLayer().add(figure);
+ }
+
+ /**
+ * Returns the layer used for displaying feedback.
+ *
+ * @return the feedback layer
+ */
+ protected IFigure getFeedbackLayer() {
+ return getLayer(LayerConstants.FEEDBACK_LAYER);
+ }
+
+ /**
+ * Convenience method to return the host's Figure.
+ *
+ * @return The host GraphicalEditPart's Figure
+ */
+ protected IFigure getHostFigure() {
+ return ((GraphicalEditPart) getHost()).getFigure();
+ }
+
+ /**
+ * Obtains the specified layer.
+ *
+ * @param layer
+ * the key identifying the layer
+ * @return the requested layer
+ */
+ protected IFigure getLayer(Object layer) {
+ return LayerManager.Helper.find(getHost()).getLayer(layer);
+ }
+
+ /**
+ * Removes the specified <code>Figure</code> from the
+ * {@link LayerConstants#FEEDBACK_LAYER}.
+ *
+ * @param figure
+ * the feedback to remove
+ */
+ protected void removeFeedback(IFigure figure) {
+ getFeedbackLayer().remove(figure);
+ }
+
+ private Range getCreationRange(CreateRequest request) {
+ Point realLocation = getRealLocation(request);
+ Range result = Range.emptyRange();
+ if (request.getSize() != null) {
+ result = new Range(realLocation.y, realLocation.y + request.getSize().height);
+ }
+ return result;
+ }
+
+ private Dimension getRealSize(ContainerCreationDescription ccdTool, CreateRequest request) {
+ Dimension realSize = request.getSize();
+ if (realSize == null) {
+ realSize = new Dimension(0, 0);
+ if (ccdTool instanceof InteractionUseCreationTool) {
+ realSize.height = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT;
+ } else if (ccdTool instanceof CombinedFragmentCreationTool) {
+ realSize.height = LayoutConstants.DEFAULT_COMBINED_FRAGMENT_HEIGHT;
+ }
+ }
+ return realSize;
+ }
+
+ private IDiagramCommandFactory getDiagramCommandFactory(EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor, List<EObject> coverage, Range creationRange) {
+ SequenceDiagram seqDiag = null;
+ EditPart host = getHost();
+ if (host instanceof SequenceDiagramEditPart) {
+ seqDiag = ((SequenceDiagramEditPart) host).getSequenceDiagram();
+ }
+
+ final DDiagramEditor diagramEditor = (DDiagramEditor) host.getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (diagramEditor == null || seqDiag == null) {
+ return null;
+ }
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(seqDiag.getNotationDiagram());
+ final Object adapter = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class);
+ final IDiagramCommandFactoryProvider cmdFactoryProvider = (IDiagramCommandFactoryProvider) adapter;
+ final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
+ return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor, coverage);
+ }
+
+ private IDiagramCommandFactory getDiagramCommandFactory(EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor, Point location) {
+ EditPart host = getHost();
+ SequenceDiagram seqDiag = EditPartsHelper.getSequenceDiagram(host);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(seqDiag.getNotationDiagram());
+ final DDiagramEditor diagramEditor = (DDiagramEditor) this.getHost().getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (diagramEditor == null) {
+ return null;
+ }
+ final Object adapter = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class);
+
+ final IDiagramCommandFactoryProvider cmdFactoryProvider = (IDiagramCommandFactoryProvider) adapter;
+ final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
+ return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor);
+ }
+
+ private IDiagramCommandFactory getDiagramCommandFactory(EObject predecessor, Point location) {
+ EditPart host = getHost();
+ SequenceDiagram seqDiag = EditPartsHelper.getSequenceDiagram(host);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(seqDiag.getNotationDiagram());
+ final DDiagramEditor diagramEditor = (DDiagramEditor) this.getHost().getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (diagramEditor == null) {
+ return null;
+ }
+ final Object adapter = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class);
+
+ final IDiagramCommandFactoryProvider cmdFactoryProvider = (IDiagramCommandFactoryProvider) adapter;
+ final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
+ return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, predecessor, location);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java
new file mode 100644
index 0000000000..961370a878
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceInteractionFeedBackBuilder.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.swt.graphics.Color;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractSequenceInteractionValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.HorizontalGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.RangeGuide;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * A builder for complex sequence move feedback.
+ *
+ * @author mporhel
+ */
+public class SequenceInteractionFeedBackBuilder {
+ /**
+ * The color to use for the horizontal feedback rules shown when
+ * moving/resizing an ISequencEvent.
+ */
+ private static final Color ISE_FEEDBACK_COLOR = ColorConstants.lightGray;
+
+ private final AbstractSequenceInteractionValidator validator;
+
+ private final IFigure feedBackLayer;
+
+ private final IGraphicalEditPart hostPart;
+
+ /**
+ * Constructor.
+ *
+ * @param validator
+ * the move validator.
+ * @param feedBackLayer
+ * the feedback layer.
+ * @param hostPart
+ * the main selected part.
+ */
+ public SequenceInteractionFeedBackBuilder(AbstractSequenceInteractionValidator validator, IFigure feedBackLayer, IGraphicalEditPart hostPart) {
+ this.validator = validator;
+ this.feedBackLayer = feedBackLayer;
+ this.hostPart = hostPart;
+ }
+
+ /**
+ * Build the command.
+ *
+ * @return a composite transactional command.
+ */
+ public Collection<Figure> buildFeedBack() {
+ Collection<Figure> feedbacks = Lists.newArrayList();
+
+ // validation on the first call;
+ validator.validate();
+
+ feedBackCreatedElements(feedbacks);
+
+ feedBackMovedElements(feedbacks);
+
+ feedBackResizedElements(feedbacks);
+
+ feedBackExpansion(feedbacks);
+
+ feedBackErrors(feedbacks);
+
+ feedBackConflicts(feedbacks);
+
+ return feedbacks;
+
+ }
+
+ private void feedBackConflicts(Collection<Figure> feedbacks) {
+ for (Integer conflict : validator.getInvalidPostions()) {
+ Point conflictingPosition = new Point(0, conflict);
+ conflictingPosition.performScale(GraphicalHelper.getZoom(hostPart));
+
+ Rectangle bounds = feedBackLayer.getBounds().getCopy();
+ bounds.y = conflictingPosition.y;
+ bounds.height = 1;
+
+ HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+ conflictGuide.setBounds(bounds);
+ feedbacks.add(conflictGuide);
+ }
+
+ for (Range conflict : validator.getInvalidRanges()) {
+ Rectangle screenRange = new Rectangle(0, conflict.getLowerBound(), 0, conflict.width());
+ screenRange.performScale(GraphicalHelper.getZoom(hostPart));
+ Range conflictRange = Range.verticalRange(screenRange);
+
+ Rectangle bounds = feedBackLayer.getBounds().getCopy();
+ bounds.y = conflictRange.getLowerBound();
+ bounds.height = Math.max(1, conflictRange.width());
+
+ RangeGuide guide = new RangeGuide(ColorConstants.red, conflictRange, true);
+ guide.setBounds(bounds);
+ feedbacks.add(guide);
+ }
+ }
+
+ private void feedBackErrors(Collection<Figure> feedbacks) {
+ for (ISequenceEvent errorEvent : validator.getEventsInError()) {
+ addFeedBack(errorEvent, ColorConstants.red, true, feedbacks, validator.getRangeFunction().apply(errorEvent));
+ }
+ }
+
+ private void addFeedBack(ISequenceEvent event, Color color, boolean fill, Collection<Figure> feedbacks, Range movedRange) {
+ Rectangle screenRange = new Rectangle(0, movedRange.getLowerBound(), 0, movedRange.width());
+ screenRange.performScale(GraphicalHelper.getZoom(hostPart));
+ Range moveRange = Range.verticalRange(screenRange);
+
+ Rectangle bounds = feedBackLayer.getBounds().getCopy();
+ if (event != null && event.isLogicallyInstantaneous()) {
+ moveRange = new Range(screenRange.getCenter().y, screenRange.getCenter().y);
+ bounds.y = moveRange.getLowerBound();
+ bounds.height = 1;
+ } else {
+ bounds.y = moveRange.getLowerBound();
+ bounds.height = Math.max(1, moveRange.width());
+ }
+
+ RangeGuide guide = new RangeGuide(color, moveRange, fill);
+ guide.setBounds(bounds);
+
+ feedbacks.add(guide);
+ }
+
+ private void feedBackExpansion(Collection<Figure> feedbacks) {
+ Rectangle bounds = feedBackLayer.getBounds().getCopy();
+ Range expansionZone = validator.getExpansionZone();
+ if (expansionZone != null && !expansionZone.isEmpty() && expansionZone.width() != 0) {
+ Rectangle screenRange = new Rectangle(0, expansionZone.getLowerBound(), 0, expansionZone.width());
+ screenRange.performScale(GraphicalHelper.getZoom(hostPart));
+ Range expand = Range.verticalRange(screenRange);
+
+ RangeGuide expansion = new RangeGuide(validator.isValid() ? ColorConstants.blue : ColorConstants.red, expand, true);
+ bounds.height = expand.width();
+ bounds.y = expand.getLowerBound();
+ expansion.setBounds(bounds);
+
+ feedbacks.add(expansion);
+ }
+ }
+
+ private void feedBackMovedElements(Collection<Figure> feedbacks) {
+ for (ISequenceEvent movedElement : Iterables.filter(validator.getMovedElements(), Predicates.not(Predicates.in(validator.getEventsInError())))) {
+ addFeedBack(movedElement, ISE_FEEDBACK_COLOR, false, feedbacks, validator.getRangeFunction().apply(movedElement));
+ }
+ }
+
+ private void feedBackCreatedElements(Collection<Figure> feedbacks) {
+ for (Range creationRange : validator.getCreatedElements()) {
+ addFeedBack(null, validator.isValid() ? ISE_FEEDBACK_COLOR : ColorConstants.red, false, feedbacks, creationRange);
+ }
+ }
+
+ private void feedBackResizedElements(Collection<Figure> feedbacks) {
+ for (ISequenceEvent movedElement : Iterables.filter(validator.getResizedStartMessages(), Predicates.not(Predicates.in(validator.getEventsInError())))) {
+ addFeedBack(movedElement, ISE_FEEDBACK_COLOR, false, feedbacks, validator.getRangeFunction().apply(movedElement));
+ }
+
+ for (ISequenceEvent movedElement : Iterables.filter(validator.getResizedEndMessages(), Predicates.not(Predicates.in(validator.getEventsInError())))) {
+ Range feedbackRange = validator.getRangeFunction().apply(movedElement);
+ Range expansionZone = validator.getExpansionZone();
+ if ((expansionZone != null && !expansionZone.isEmpty()) && feedbackRange.includes(expansionZone.getUpperBound())) {
+ feedbackRange = new Range(feedbackRange.getLowerBound(), feedbackRange.getUpperBound() - expansionZone.width());
+ }
+ addFeedBack(movedElement, ISE_FEEDBACK_COLOR, false, feedbacks, feedbackRange);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceLaunchToolEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceLaunchToolEditPolicy.java
new file mode 100644
index 0000000000..2e215d45c2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceLaunchToolEditPolicy.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.description.tool.PaneBasedSelectionWizardDescription;
+import org.eclipse.sirius.description.tool.SelectionWizardDescription;
+import org.eclipse.sirius.description.tool.ToolDescription;
+import org.eclipse.sirius.diagram.graphical.edit.policies.CreationUtil;
+import org.eclipse.sirius.diagram.graphical.edit.policies.LaunchToolEditPolicy;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command.SequenceDelegatingCommandFactory;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+
+/**
+ * Edit policy for launching tools. Adding the support of $endBefore variable.
+ *
+ * @author mporhel
+ */
+public class SequenceLaunchToolEditPolicy extends LaunchToolEditPolicy {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected CreationUtil getCreationUtil(CreateRequest request, Point location, EditPart editPart, IDiagramCommandFactory baseEmfCommandFactory) {
+ IDiagramCommandFactory launchToolCommandFactory = baseEmfCommandFactory;
+
+ Object tool = request.getNewObject();
+ if (tool instanceof ToolDescription || tool instanceof PaneBasedSelectionWizardDescription || tool instanceof SelectionWizardDescription) {
+ launchToolCommandFactory = getLaunchToolCommandFactory(editPart, request.getLocation().getCopy(), baseEmfCommandFactory);
+ }
+
+ return super.getCreationUtil(request, location, editPart, launchToolCommandFactory);
+ }
+
+ private IDiagramCommandFactory getLaunchToolCommandFactory(EditPart editPart, Point requestLocation, IDiagramCommandFactory baseEmfCommandFactory) {
+ IDiagramCommandFactory result = baseEmfCommandFactory;
+
+ Point location = requestLocation.getCopy();
+ if (editPart instanceof IGraphicalEditPart) {
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) editPart);
+ }
+
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(editPart);
+ if (sequenceDiagram != null) {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(sequenceDiagram.getNotationDiagram());
+ SequenceDDiagram diagram = sequenceDiagram.getSequenceDDiagram();
+ EventEnd endBefore = SequenceGraphicalHelper.getEndBefore(diagram, location.y);
+ result = new SequenceDelegatingCommandFactory(baseEmfCommandFactory, domain, sequenceDiagram, endBefore, location.getCopy());
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java
new file mode 100644
index 0000000000..e33f15d674
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceMessageEditPolicy.java
@@ -0,0 +1,852 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Cursors;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.PositionConstants;
+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.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.AbstractEMFOperation;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.BendpointRequest;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+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.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ConnectionBendpointEditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.internal.commands.SetConnectionBendpointsCommand;
+import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.swt.graphics.Color;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.EndOfLifeMoveOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetMessageRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.ShiftDirectSubExecutionsOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceMessageViewQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.EndOfLifeOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.ShiftDescendantMessagesOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.EndOfLifeEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.PositionsChecker;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.HorizontalGuide;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * Specialized edit policy for sequence diagrams messages: tracks graphical
+ * reordering and invokes user-specified reordering tool to reflect the changes
+ * in the semantic model.
+ * <p>
+ * This edit policy should only be installed on SequenceMessageEditParts.
+ *
+ * @author pcdavid
+ */
+public class SequenceMessageEditPolicy extends ConnectionBendpointEditPolicy {
+
+ /**
+ * Key constant use for request from a BendpointRequest on Message.
+ */
+ public static final String REQUEST_FROM_SEQUENCE_MESSAGE_EDIT_POLICY = "Request a Execution resize from a BendpointRequest";
+
+ /**
+ * The color top use for the horizontal feedback rules shown when moving a
+ * message.
+ */
+ private static final Color MESSAGE_FEEDBACK_COLOR = ColorConstants.lightGray;
+
+ private final Collection<Figure> guides = Lists.newArrayList();
+
+ /**
+ * Saves the validation status of the command on bendpoint move.
+ */
+ private boolean invalidCommand;
+
+ /**
+ * Overridden to check that we are only installed on sequence messages.
+ */
+ @Override
+ @SuppressWarnings("restriction")
+ public void activate() {
+ Preconditions.checkState(getHost() instanceof SequenceMessageEditPart);
+ super.activate();
+ }
+
+ protected SequenceMessageEditPart getMessage() {
+ return (SequenceMessageEditPart) getHost();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addInvisibleCreationHandle(@SuppressWarnings("rawtypes") List list, ConnectionEditPart connEP, int i) {
+ /*
+ * Do nothing: the handles created by default use a raw GEF drag tracker
+ * which we do not control, and which can lead to disconnections of
+ * branches on reflective messages.
+ *
+ */
+ }
+
+ /**
+ * Update the location of the horizontal feedback line.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("restriction")
+ public void showSourceFeedback(Request request) {
+ removeFeedBackOnGuides();
+
+ if (request instanceof BendpointRequest) {
+ BendpointRequest br = (BendpointRequest) request;
+ SequenceMessageEditPart thisEvent = (SequenceMessageEditPart) getHost();
+ ISequenceEvent iSequenceEvent = thisEvent.getISequenceEvent();
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(iSequenceEvent);
+ super.showSourceFeedback(request);
+
+ MoveType moveType = getMoveType(thisEvent, br, ends);
+ if (moveType.needsCompoundMove()) {
+ showCompoundEndFeedback(br, thisEvent, ends, moveType.isFromTop());
+ } else {
+ Point location = new Point(1, thisEvent.getConnectionFigure().getPoints().getFirstPoint().y);
+ location.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+
+ Figure guide = new HorizontalGuide(MESSAGE_FEEDBACK_COLOR, location.y);
+ Rectangle bounds = getFeedbackLayer().getBounds().getCopy();
+ bounds.height = 1;
+ bounds.y = location.y;
+ guide.setBounds(bounds);
+ addFeedback(guide);
+ guides.add(guide);
+
+ if (new ISequenceEventQuery(getMessage().getISequenceEvent()).isReflectiveMessage()) {
+ Point endLocation = new Point(1, thisEvent.getConnectionFigure().getPoints().getLastPoint().y);
+ endLocation.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+ Figure messageToSelfBottomGuide = new HorizontalGuide(MESSAGE_FEEDBACK_COLOR, endLocation.y);
+ bounds = getFeedbackLayer().getBounds().getCopy();
+ bounds.height = 1;
+ bounds.y = endLocation.y;
+ messageToSelfBottomGuide.setBounds(bounds);
+ addFeedback(messageToSelfBottomGuide);
+ guides.add(messageToSelfBottomGuide);
+ }
+
+ if (thisEvent.getTarget() instanceof InstanceRoleEditPart) {
+ showInstanceRoleFeedback(br);
+ } else if (thisEvent.getTarget() instanceof EndOfLifeEditPart) {
+ showEndOfLifeFeedback(br);
+ }
+
+ Point reqLoc = br.getLocation().getCopy();
+ GraphicalHelper.screen2logical(reqLoc, (IGraphicalEditPart) getHost());
+ Option<Range> finalRange = computeFinalRange(br, thisEvent, reqLoc);
+ if (finalRange.some()) {
+ Collection<Integer> invalidPositions = checkGlobalPositions(iSequenceEvent, finalRange);
+ for (Integer conflict : invalidPositions) {
+ bounds = getFeedbackLayer().getBounds().getCopy();
+
+ Point conflictingPosition = new Point(0, conflict);
+ conflictingPosition.performScale(GraphicalHelper.getZoom((IGraphicalEditPart) getHost()));
+
+ HorizontalGuide conflictGuide = new HorizontalGuide(ColorConstants.red, conflictingPosition.y);
+ bounds.y = conflictingPosition.y;
+ bounds.height = 1;
+ conflictGuide.setBounds(bounds);
+ addFeedback(conflictGuide);
+ guides.add(conflictGuide);
+ }
+ }
+ }
+ }
+ }
+
+ private void removeFeedBackOnGuides() {
+ for (Figure fig : guides) {
+ removeFeedback(fig);
+ }
+ guides.clear();
+
+ }
+
+ private void showCompoundEndFeedback(BendpointRequest request, SequenceMessageEditPart thisEvent, List<EventEnd> ends, boolean fromTop) {
+ final EObject thisSemanticEvent = thisEvent.resolveTargetSemanticElement();
+ final SequenceDiagramEditPart sdep = EditPartsHelper.getSequenceDiagramPart(thisEvent);
+ final Range thisRange = thisEvent.getISequenceEvent().getVerticalRange();
+ final Point location = request.getLocation().getCopy();
+
+ final Predicate<SingleEventEnd> toMove = new Predicate<SingleEventEnd>() {
+ public boolean apply(SingleEventEnd input) {
+ return !input.getSemanticEvent().equals(thisSemanticEvent);
+ }
+ };
+
+ Dimension resizeDelta = getResizeDelta(location.getCopy(), thisEvent, thisRange, fromTop);
+ for (CompoundEventEnd cee : Iterables.filter(ends, CompoundEventEnd.class)) {
+ for (SingleEventEnd see : Iterables.filter(Lists.newArrayList(cee.getEventEnds()), toMove)) {
+ ISequenceEventEditPart ise = EditPartsHelper.findISequenceEvent(see, sdep);
+ ChangeBoundsRequest cbr = buildChangeBoundRequest(location.getCopy(), thisEvent, see, resizeDelta);
+ ise.showSourceFeedback(cbr);
+ }
+ }
+ }
+
+ private void eraseCompoundEndFeedback(BendpointRequest request, SequenceMessageEditPart thisEvent, List<EventEnd> ends, boolean fromTop) {
+ final EObject thisSemanticEvent = thisEvent.resolveTargetSemanticElement();
+ final SequenceDiagramEditPart sdep = EditPartsHelper.getSequenceDiagramPart(thisEvent);
+ final Range thisRange = thisEvent.getISequenceEvent().getVerticalRange();
+ final Point location = request.getLocation().getCopy();
+
+ final Predicate<SingleEventEnd> toMove = new Predicate<SingleEventEnd>() {
+ public boolean apply(SingleEventEnd input) {
+ return !input.getSemanticEvent().equals(thisSemanticEvent);
+ }
+ };
+
+ Dimension resizeDelta = getResizeDelta(location.getCopy(), thisEvent, thisRange, fromTop);
+ for (CompoundEventEnd cee : Iterables.filter(ends, CompoundEventEnd.class)) {
+ for (SingleEventEnd see : Iterables.filter(Lists.newArrayList(cee.getEventEnds()), toMove)) {
+ ISequenceEventEditPart ise = EditPartsHelper.findISequenceEvent(see, sdep);
+ ChangeBoundsRequest cbr = buildChangeBoundRequest(location.getCopy(), thisEvent, see, resizeDelta);
+ ise.eraseSourceFeedback(cbr);
+ }
+ }
+ }
+
+ /**
+ * Moving a create message up and down will also show the feedback of the
+ * targeted instance role.
+ *
+ * @param request
+ * the "create message" move request
+ */
+ private void showInstanceRoleFeedback(BendpointRequest request) {
+ InstanceRoleEditPart target = (InstanceRoleEditPart) ((SequenceMessageEditPart) getHost()).getTarget();
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ Point scrollSize = GraphicalHelper.getScrollSize(target);
+ IGraphicalEditPart source = (IGraphicalEditPart) ((SequenceMessageEditPart) getHost()).getSource();
+ int feedbackRangeLimit = request.getLocation().y;
+ Rectangle sourceBbounds = source.getFigure().getBounds();
+
+ // limit the vertical move to the first sequence event of the targeted
+ // instance role
+ int firstMessageInTargetInstanceRole = Integer.MAX_VALUE;
+
+ LifelineEditPart lifelineEditPart = Iterables.getOnlyElement(EditPartsHelper.getAllLifelines(target));
+ Range occupiedRange = lifelineEditPart.getISequenceEvent().getOccupiedRange();
+ if (!occupiedRange.isEmpty()) {
+ // limite the move to the first sequence event of the target
+ // lifeline
+ firstMessageInTargetInstanceRole = occupiedRange.getLowerBound() - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ }
+
+ if (feedbackRangeLimit < sourceBbounds.y + LayoutConstants.EXECUTION_CHILDREN_MARGIN) {
+ feedbackRangeLimit = sourceBbounds.y + LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ } else if (firstMessageInTargetInstanceRole < feedbackRangeLimit + LayoutConstants.EXECUTION_CHILDREN_MARGIN) {
+ feedbackRangeLimit = firstMessageInTargetInstanceRole - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ } else if (feedbackRangeLimit + GraphicalHelper.getScrollSize(target).y > sourceBbounds.y + sourceBbounds.height - LayoutConstants.EXECUTION_CHILDREN_MARGIN) {
+ feedbackRangeLimit = sourceBbounds.y + sourceBbounds.height - GraphicalHelper.getScrollSize(target).y - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ }
+
+ cbr.getMoveDelta().y = feedbackRangeLimit - (target.getFigure().getBounds().y + target.getFigure().getBounds().height / 2) + scrollSize.y; // br.getLocation().y
+ target.showSourceFeedback(cbr);
+ }
+
+ /**
+ * Moving a destroy message up and down will also show the feedback of the
+ * targeted end of life.
+ *
+ * @param request
+ * the "create message" move request
+ */
+ private void showEndOfLifeFeedback(Request request) {
+ EndOfLifeEditPart endOfLifeEditPart = (EndOfLifeEditPart) ((SequenceMessageEditPart) getHost()).getTarget();
+ EndOfLifeOperations.showEndOfLifeFeedback(request, endOfLifeEditPart, (IGraphicalEditPart) ((SequenceMessageEditPart) getHost()).getSource());
+ }
+
+ /**
+ * Remove the the horizontal feedback line.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("restriction")
+ public void eraseSourceFeedback(Request request) {
+ removeFeedBackOnGuides();
+
+ super.eraseSourceFeedback(request);
+
+ if (request instanceof BendpointRequest) {
+ SequenceMessageEditPart thisEvent = (SequenceMessageEditPart) getHost();
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(((ISequenceEventEditPart) getHost()).getISequenceEvent());
+ BendpointRequest br = (BendpointRequest) request;
+ // thisEvent.setCursor(org.eclipse.gmf.runtime.gef.ui.internal.l10n.Cursors.CURSOR_SEG_MOVE);
+ if (thisEvent.getTarget() instanceof InstanceRoleEditPart) {
+ InstanceRoleEditPart target = (InstanceRoleEditPart) thisEvent.getTarget();
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ cbr.getMoveDelta().y = br.getLocation().y - (target.getFigure().getBounds().y + target.getFigure().getBounds().height / 2); // br.getLocation().y
+ target.eraseSourceFeedback(cbr);
+ } else if (thisEvent.getTarget() instanceof EndOfLifeEditPart) {
+ EndOfLifeOperations.eraseEndOfLifeFeedback((LifelineEditPart) thisEvent.getTarget().getParent(), br);
+ } else {
+ MoveType moveType = getMoveType(thisEvent, br, ends);
+ if (moveType.needsCompoundMove()) {
+ eraseCompoundEndFeedback(br, thisEvent, ends, moveType.isFromTop());
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EditPart getTargetEditPart(Request request) {
+ if (RequestConstants.REQ_SET_ALL_BENDPOINT.equals(request.getType())) {
+ return getHost();
+ } else {
+ return super.getTargetEditPart(request);
+ }
+ }
+
+ /**
+ * Change the place of the message in the semantic model if the new
+ * graphical positions requires it.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getBendpointsChangedCommand(BendpointRequest request) {
+ invalidCommand = false;
+
+ SequenceMessageEditPart thisEvent = (SequenceMessageEditPart) getHost();
+ Command result;
+ Command baseCommand = super.getBendpointsChangedCommand(request);
+ ICommand smrc = null;
+
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+
+ Option<Range> finalRange = computeFinalRange(request, thisEvent, location);
+
+ if (finalRange.some()) {
+ smrc = createReconnectionCommandOnBendpointMove(request, thisEvent, location, finalRange.get());
+ }
+
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(thisEvent.getISequenceEvent());
+ invalidCommand = invalidCommand || !baseCommand.canExecute() || !finalRange.some();
+ invalidCommand = invalidCommand || org.eclipse.gef.RequestConstants.REQ_MOVE_BENDPOINT.equals(request.getType());
+ invalidCommand = invalidCommand || !validateMessageParentOperand(finalRange);
+ invalidCommand = invalidCommand || !checkGlobalPositions(thisEvent.getISequenceEvent(), finalRange).isEmpty();
+
+ if (invalidCommand) {
+ thisEvent.setCursor(org.eclipse.draw2d.Cursors.NO);
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ String label = baseCommand.getLabel();
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(thisEvent.getEditingDomain(), (label != null ? label : "<null>") + " and synchronize ordering");
+ SequenceEditPartsOperations.appendFullRefresh(thisEvent, ctc);
+
+ MoveType move = getMoveType(thisEvent, request, ends);
+ if (move.needsCompoundMove()) {
+ addCompoundEventCommands(ctc, thisEvent, ends, request, move.isFromTop());
+ thisEvent.setCursor(Cursors.SIZENS);
+ } else {
+ /*
+ * Overridden to handle lifeline move/resize when moving the
+ * selected create/destroy message.
+ */
+ if (thisEvent.getTarget() instanceof InstanceRoleEditPart) {
+ ctc.compose(getMoveCreateMessageCommand(request, thisEvent, baseCommand));
+ } else if (thisEvent.getTarget() instanceof EndOfLifeEditPart) {
+ ctc.compose(getMoveDestroyMessageCommand(request, thisEvent, baseCommand));
+ }
+ ctc.compose(smrc);
+
+ SequenceEditPartsOperations.addRefreshGraphicalOrderingCommand(ctc, thisEvent);
+ SequenceEditPartsOperations.addSynchronizeSemanticOrderingCommand(ctc, thisEvent.getISequenceEvent());
+ thisEvent.setCursor(org.eclipse.gmf.runtime.gef.ui.internal.l10n.Cursors.CURSOR_SEG_MOVE);
+ }
+
+ SequenceEditPartsOperations.appendFullRefresh(thisEvent, ctc);
+ // if (!(thisEvent.getTarget() instanceof EndOfLifeEditPart ||
+ // thisEvent.getTarget() instanceof InstanceRoleEditPart)) {
+ // addRequestLayout(cc, thisEvent);
+ // }
+
+ if (!ctc.canExecute()) {
+ thisEvent.setCursor(org.eclipse.draw2d.Cursors.NO);
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ result = new ICommandProxy(ctc);
+ }
+ }
+ return result;
+ }
+
+ private Collection<Integer> checkGlobalPositions(final ISequenceEvent thisEvent, final Option<Range> finalRange) {
+ Function<ISequenceEvent, Range> futureRangeFunction = new Function<ISequenceEvent, Range>() {
+ public Range apply(ISequenceEvent from) {
+ Range verticalRange = from.getVerticalRange();
+ if (thisEvent.equals(from) && finalRange.some()) {
+ verticalRange = finalRange.get();
+ }
+ return verticalRange;
+ }
+ };
+ return new PositionsChecker(thisEvent.getDiagram(), futureRangeFunction).getInvalidPositions();
+ }
+
+ private ICommand createReconnectionCommandOnBendpointMove(BendpointRequest request, SequenceMessageEditPart thisEvent, Point location, Range finalRange) {
+ SetMessageRangeOperation smrc = new SetMessageRangeOperation((Edge) thisEvent.getNotationView(), finalRange);
+ Message message = (Message) thisEvent.getISequenceEvent();
+ boolean reflectiveMessage = message.isReflective();
+
+ setOperations(true, message, finalRange, smrc, reflectiveMessage);
+ setOperations(false, message, finalRange, smrc, reflectiveMessage);
+
+ return CommandFactory.createICommand(thisEvent.getEditingDomain(), smrc);
+ }
+
+ private void setOperations(boolean source, Message message, Range finalRange, SetMessageRangeOperation smrc, boolean reflectiveMessage) {
+ Range messageEndRange = source ? new Range(finalRange.getLowerBound(), finalRange.getLowerBound()) : new Range(finalRange.getUpperBound(), finalRange.getUpperBound());
+ ISequenceNode currentEnd = source ? message.getSourceElement() : message.getTargetElement();
+ Option<Lifeline> endLifeline = currentEnd.getLifeline();
+ if (endLifeline.some() && currentEnd instanceof ISequenceEvent) {
+ ISequenceEvent finalEnd;
+ Range finalEndRange;
+
+ EventFinder endFinder = new EventFinder(endLifeline.get());
+ endFinder.setReconnection(true);
+
+ if (!reflectiveMessage) {
+ finalEnd = endFinder.findMostSpecificEvent(finalRange);
+ } else {
+ finalEnd = (ISequenceEvent) currentEnd;
+
+ boolean compoundSrc = finalEnd instanceof Execution && message.equals(source ? ((Execution) finalEnd).getEndMessage().get() : ((Execution) finalEnd).getStartMessage().get());
+ if (!compoundSrc && !finalEnd.equals(endFinder.findMostSpecificEvent(messageEndRange))) {
+ // It is not allowed to reconnect a reflexive message by
+ // moving bendpoints
+ invalidCommand = true;
+ }
+
+ // look for event source
+ endFinder.setReconnection(false);
+ ISequenceEvent potentialSource = endFinder.findMostSpecificEvent(messageEndRange);
+ if (potentialSource instanceof CombinedFragment) {
+ invalidCommand = true;
+ }
+ }
+
+ // finalSrc can be null while moving a message under its lifeline.
+ // finalTgt cannot be null : restrain the capability to move out of
+ // lifeline for destruction messages.
+ if (source && finalEnd == null) {
+ finalEnd = (ISequenceEvent) currentEnd;
+ }
+
+ // look for event end (source/target)
+ endFinder.setReconnection(false);
+ ISequenceEvent realEnd = endFinder.findMostSpecificEvent(finalRange);
+ if (realEnd == null) {
+ // realEnd can be null while moving a message under its
+ // lifeline
+ realEnd = (ISequenceEvent) currentEnd;
+ }
+
+ boolean noValidation = reflectiveMessage || realEnd instanceof Lifeline;
+ if (!invalidCommand) {
+ if (finalEnd != null && (noValidation || realEnd != null && realEnd.canChildOccupy(message, finalRange))) {
+ finalEndRange = finalEnd.getVerticalRange();
+ Rectangle endBounds = new Rectangle(0, finalEndRange.getLowerBound(), 0, finalEndRange.width());
+ if (source) {
+ smrc.setSource(finalEnd.getNotationView(), endBounds);
+ } else {
+ smrc.setTarget(finalEnd.getNotationView(), endBounds);
+ }
+ } else {
+ // The message is moved beyond the lifeline range
+ invalidCommand = true;
+ }
+ }
+ } else if (currentEnd instanceof LostMessageEnd || currentEnd instanceof EndOfLife || currentEnd instanceof InstanceRole) {
+ Rectangle finalEndBounds = currentEnd.getProperLogicalBounds().getCopy();
+ if (source) {
+ smrc.setSource(currentEnd.getNotationView(), finalEndBounds);
+ } else {
+ smrc.setTarget(currentEnd.getNotationView(), finalEndBounds);
+ }
+ }
+
+ }
+
+ private Option<Range> computeFinalRange(BendpointRequest request, SequenceMessageEditPart smep, Point location) {
+ Range finalRange = null;
+ if (!new ISequenceEventQuery(smep.getISequenceEvent()).isReflectiveMessage()) {
+ finalRange = new Range(location.y, location.y);
+ } else {
+ Edge edge = (Edge) smep.getNotationView();
+ SequenceMessageViewQuery query = new SequenceMessageViewQuery(edge);
+
+ int firstPointVerticalPosition = query.getFirstPointVerticalPosition(true);
+ int lastPointVerticalPosition = query.getLastPointVerticalPosition(true);
+
+ switch (request.getIndex()) {
+ case 0:
+ finalRange = safeComputeMessageToSelfFinalRangeFromTop(location, lastPointVerticalPosition);
+ break;
+ case 2:
+ finalRange = safeComputeMessageToSelfFinalRangeFromBottom(firstPointVerticalPosition, location);
+ break;
+ case 1:
+ default:
+ finalRange = new Range(firstPointVerticalPosition, lastPointVerticalPosition);
+ break;
+ }
+ }
+ return Options.newSome(finalRange);
+ }
+
+ private Range safeComputeMessageToSelfFinalRangeFromBottom(int firstPointVerticalPosition, Point newBottomLocation) {
+ if (newBottomLocation.y >= firstPointVerticalPosition + LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP) {
+ return new Range(firstPointVerticalPosition, newBottomLocation.y);
+ }
+ invalidCommand = true;
+ return null;
+ }
+
+ private Range safeComputeMessageToSelfFinalRangeFromTop(Point newTopLocation, int lastPointVerticalPosition) {
+ if (newTopLocation.y <= lastPointVerticalPosition - LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP) {
+ return new Range(newTopLocation.y, lastPointVerticalPosition);
+ }
+ invalidCommand = true;
+ return null;
+ }
+
+ private MoveType getMoveType(SequenceMessageEditPart event, BendpointRequest request, List<EventEnd> ends) {
+ boolean compoundMove = !Iterables.isEmpty(Iterables.filter(ends, CompoundEventEnd.class));
+ boolean msgToSelfMove = new ISequenceEventQuery(event.getISequenceEvent()).isReflectiveMessage();
+ boolean needsCompoundEventCommands = compoundMove && !msgToSelfMove;
+ boolean fromTop = true;
+ if (compoundMove && msgToSelfMove && ends.size() == 2) {
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, event);
+ if (request.getExtendedData().containsKey(SequenceMessageEditPart.MSG_TO_SELF_TOP_MOVE)) {
+ fromTop = (Boolean) request.getExtendedData().get(SequenceMessageEditPart.MSG_TO_SELF_TOP_MOVE);
+ needsCompoundEventCommands = fromTop ? ends.get(0) instanceof CompoundEventEnd : ends.get(1) instanceof CompoundEventEnd;
+ } else {
+ needsCompoundEventCommands = false;
+ }
+ }
+ return new MoveType(needsCompoundEventCommands, fromTop);
+ }
+
+ private void addCompoundEventCommands(CompositeTransactionalCommand ctc, final SequenceMessageEditPart thisEvent, List<EventEnd> ends, BendpointRequest request, boolean fromTop) {
+ final EObject thisSemanticEvent = thisEvent.resolveTargetSemanticElement();
+ final SequenceDiagramEditPart sdep = EditPartsHelper.getSequenceDiagramPart(thisEvent);
+ final Range thisRange = thisEvent.getISequenceEvent().getVerticalRange();
+ final Point location = request.getLocation().getCopy();
+
+ final Predicate<SingleEventEnd> toMove = new Predicate<SingleEventEnd>() {
+ public boolean apply(SingleEventEnd input) {
+ return !input.getSemanticEvent().equals(thisSemanticEvent);
+ }
+ };
+
+ Dimension resizeDelta = getResizeDelta(location.getCopy(), thisEvent, thisRange, fromTop);
+ for (CompoundEventEnd cee : Iterables.filter(ends, CompoundEventEnd.class)) {
+ for (SingleEventEnd see : Iterables.filter(Lists.newArrayList(cee.getEventEnds()), toMove)) {
+ ISequenceEventEditPart ise = EditPartsHelper.findISequenceEvent(see, sdep);
+ ISequenceEvent sequenceEvent = ise.getISequenceEvent();
+ ChangeBoundsRequest cbr = buildChangeBoundRequest(location.getCopy(), ise, see, resizeDelta);
+ if (sequenceEvent instanceof AbstractNodeEvent) {
+ // if sequenveEvent is Execution, we must indicates to the
+ // ExecutionSelectionValidator that we want resize its
+ // Execution
+ cbr.getExtendedData().put(REQUEST_FROM_SEQUENCE_MESSAGE_EDIT_POLICY, true);
+ }
+ ctc.compose(new CommandProxy(ise.getCommand(cbr)));
+ }
+ }
+ }
+
+ private ChangeBoundsRequest buildChangeBoundRequest(Point point, ISequenceEventEditPart ise, SingleEventEnd see, Dimension resizeDelta) {
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ cbr.setLocation(point);
+ cbr.setEditParts(ise);
+ cbr.setConstrainedResize(true);
+ if (see.isStart()) {
+ cbr.setResizeDirection(PositionConstants.NORTH);
+ cbr.setMoveDelta(new Point(0, resizeDelta.height));
+ cbr.setSizeDelta(resizeDelta.getNegated());
+ cbr.setConstrainedMove(true);
+ } else {
+ cbr.setResizeDirection(PositionConstants.SOUTH);
+ cbr.setSizeDelta(resizeDelta);
+ cbr.setConstrainedResize(true);
+ }
+ return cbr;
+ }
+
+ private Dimension getResizeDelta(Point location, ISequenceEventEditPart ise, Range range, boolean fromTop) {
+ GraphicalHelper.screen2logical(location, ise);
+ int deltaY = location.y - (fromTop ? range.getLowerBound() : range.getUpperBound());
+ deltaY = (int) (deltaY * GraphicalHelper.getZoom(ise));
+ return new Dimension(0, deltaY);
+ }
+
+ /**
+ * Overridden to resize the targeted RoteExecitionEditPart when moving the
+ * selected destroy message.
+ *
+ * @param baseCommand
+ * @param smep
+ *
+ * @param request
+ * the current request
+ * @return a compound command if the destroy message is moved, the super
+ * command otherwise
+ */
+ private AbstractEMFOperation getMoveDestroyMessageCommand(BendpointRequest br, SequenceMessageEditPart smep, Command baseCommand) {
+ CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(smep.getEditingDomain(), "Move create message");
+ if (smep.getSource() instanceof ISequenceEventEditPart) {
+ ISequenceEventEditPart source = (ISequenceEventEditPart) smep.getSource();
+ Range sourceRange = source.getISequenceEvent().getVerticalRange();
+ Range lowerLimit = new Range(sourceRange.getLowerBound() - LayoutConstants.EXECUTION_CHILDREN_MARGIN, sourceRange.getLowerBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+ Range upperLimit = new Range(sourceRange.getUpperBound() - LayoutConstants.EXECUTION_CHILDREN_MARGIN, sourceRange.getUpperBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+
+ Point wantedLocation = br.getLocation().getCopy();
+ GraphicalHelper.screen2logical(wantedLocation, smep);
+ if (lowerLimit.includes(wantedLocation.y) || upperLimit.includes(wantedLocation.y)) {
+ ctc.compose(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
+ return ctc;
+ }
+ }
+ EndOfLifeEditPart endOfLifeEditPart = (EndOfLifeEditPart) smep.getTarget();
+ final LifelineEditPart lifelineEditPart = (LifelineEditPart) endOfLifeEditPart.getParent();
+
+ ChangeBoundsRequest cbr = SequenceMessageEditPolicy.getEndOfLifeMoveRequest(endOfLifeEditPart, br.getLocation().getCopy());
+ if (cbr != null) {
+ ctc.compose(new CommandProxy(endOfLifeEditPart.getCommand(cbr)));
+ } else {
+ ctc.compose(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
+ }
+
+ if (ctc.canExecute()) {
+ ctc.compose(new CommandProxy(baseCommand));
+ updateMovingTargetReferencePoint(baseCommand, cbr);
+ TransactionalEditingDomain editingDomain = smep.getEditingDomain();
+ ctc.compose(CommandFactory.createICommand(editingDomain, new ShiftDescendantMessagesOperation(lifelineEditPart.getISequenceEvent(), cbr.getSizeDelta().height, true, false, false)));
+ }
+ return ctc;
+ }
+
+ private static ChangeBoundsRequest getEndOfLifeMoveRequest(EndOfLifeEditPart endOfLifeEditPart, Point location) {
+ ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ cbr.setEditParts(endOfLifeEditPart);
+ cbr.setLocation(location.getCopy());
+ cbr.setConstrainedMove(true);
+
+ double zoom = GraphicalHelper.getZoom(endOfLifeEditPart);
+ GraphicalHelper.screen2logical(location, endOfLifeEditPart);
+ Rectangle bounds = endOfLifeEditPart.getFigure().getBounds();
+ int delta = location.y - (bounds.getCenter().y);
+ cbr.setMoveDelta(new Point(0, delta * zoom));
+ return cbr;
+ }
+
+ /**
+ * Overridden to move the targeted InstanceRoleEditPart when moving the
+ * selected create message.
+ *
+ * @param request
+ * the current request
+ * @param baseCommand
+ * @return a compound command if the create message is moved, the super
+ * command otherwise
+ */
+ private AbstractEMFOperation getMoveCreateMessageCommand(BendpointRequest request, SequenceMessageEditPart smep, Command baseCommand) {
+ Point normalizedLocation = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(normalizedLocation, smep);
+
+ InstanceRoleEditPart instanceRoleEditPart = (InstanceRoleEditPart) smep.getTarget();
+ LifelineEditPart lifelineEditPart = Iterables.getOnlyElement(EditPartsHelper.getAllLifelines(instanceRoleEditPart));
+
+ CompositeTransactionalCommand cc = new CompositeTransactionalCommand(smep.getEditingDomain(), "Move create message");
+
+ // limite the move to the first sequence event of the target
+ int firstMessageInTargetInstanceRole = lifelineEditPart.getISequenceEvent().getVerticalRange().getUpperBound() - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ Range occupiedRange = lifelineEditPart.getISequenceEvent().getOccupiedRange();
+ if (!occupiedRange.isEmpty()) {
+ // limite the move to the first sequence event of the target
+ firstMessageInTargetInstanceRole = occupiedRange.getLowerBound() - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ }
+
+ int sourceRangeLimit = computeSourceRangeLimit(smep, normalizedLocation, firstMessageInTargetInstanceRole);
+ if (normalizedLocation.y > sourceRangeLimit) {
+ cc.compose(org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand.INSTANCE);
+ return cc;
+ }
+
+ final ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ cbr.getMoveDelta().y = sourceRangeLimit - (instanceRoleEditPart.getFigure().getBounds().y + instanceRoleEditPart.getFigure().getBounds().height / 2);
+ cbr.setConstrainedMove(true);
+ cbr.setEditParts(instanceRoleEditPart);
+ cc.compose(new CommandProxy(instanceRoleEditPart.getCommand(cbr)));
+ cc.compose(new CommandProxy(baseCommand));
+
+ /*
+ * These additional commands adjust the positions of the executions and
+ * messages on the lifeline so that visually they do not move. They are
+ * dual to the commands we add when moving a normal execution, as in
+ * that case we want all the executions and messages it contains to move
+ * along.
+ */
+ final LifelineEditPart lep = EditPartsHelper.getAllLifelines(instanceRoleEditPart).get(0);
+
+ // Avoid EndOfLife Move
+ TransactionalEditingDomain editingDomain = smep.getEditingDomain();
+ cc.compose(CommandFactory.createICommand(editingDomain, new EndOfLifeMoveOperation((Lifeline) lep.getISequenceEvent(), -cbr.getMoveDelta().y)));
+ cc.compose(CommandFactory.createICommand(editingDomain, new ShiftDirectSubExecutionsOperation(lep.getISequenceEvent(), -cbr.getMoveDelta().y)));
+ cc.compose(CommandFactory.createICommand(editingDomain, new ShiftDescendantMessagesOperation(lep.getISequenceEvent(), cbr.getMoveDelta().y, true, false, true)));
+
+ return cc;
+ }
+
+ private void updateMovingTargetReferencePoint(Command baseCommand, final ChangeBoundsRequest cbr) {
+ if (baseCommand instanceof ICommandProxy && ((ICommandProxy) baseCommand).getICommand() instanceof SetConnectionBendpointsCommand) {
+ /*
+ * Update target reference point of the SetConnectionBendpoint base
+ * command to take into account he move ot the instance role.
+ */
+ SetConnectionBendpointsCommand scbc = (SetConnectionBendpointsCommand) ((ICommandProxy) baseCommand).getICommand();
+ scbc.setNewPointList(scbc.getNewPointList(), scbc.getSourceRefPoint(), scbc.getTargetRefPoint().getCopy().getTranslated(cbr.getMoveDelta()));
+ }
+ }
+
+ private int computeSourceRangeLimit(SequenceMessageEditPart smep, Point normalizedLocation, int firstMessageInTargetInstanceRole) {
+ int sourceRangeLimit = normalizedLocation.y;
+ Range sourceRange = smep.getISequenceEvent().getVerticalRange();
+ Range lowerLimit = new Range(sourceRange.getLowerBound(), sourceRange.getLowerBound() + LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+ Range upperLimit = new Range(sourceRange.getUpperBound() - LayoutConstants.EXECUTION_CHILDREN_MARGIN, sourceRange.getUpperBound());
+
+ if (firstMessageInTargetInstanceRole < sourceRangeLimit + LayoutConstants.EXECUTION_CHILDREN_MARGIN) {
+ sourceRangeLimit = firstMessageInTargetInstanceRole - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ } else if (lowerLimit.includes(sourceRangeLimit)) {
+ sourceRangeLimit = lowerLimit.getUpperBound();
+ } else if (upperLimit.includes(sourceRangeLimit)) {
+ sourceRangeLimit = upperLimit.getLowerBound();
+ }
+ return sourceRangeLimit;
+ }
+
+ private boolean validateMessageParentOperand(Option<Range> finalRange) {
+ boolean valid = true;
+
+ SequenceMessageEditPart thisEvent = (SequenceMessageEditPart) getHost();
+ Message message = (Message) thisEvent.getISequenceEvent();
+ Option<Lifeline> sourceLifeline = message.getSourceLifeline();
+ Option<Lifeline> targetLifeline = message.getTargetLifeline();
+
+ if (finalRange.some() && sourceLifeline.some() && targetLifeline.some()) {
+ Option<Operand> sourceFinalOperand = Options.newNone();
+ Option<Operand> targetFinalOperand = Options.newNone();
+
+ if (sourceLifeline.get().equals(targetLifeline.get())) {
+ int lBound = finalRange.get().getLowerBound();
+ int uBound = finalRange.get().getUpperBound();
+
+ sourceFinalOperand = sourceLifeline.get().getParentOperand(new Range(lBound, lBound));
+ targetFinalOperand = targetLifeline.get().getParentOperand(new Range(uBound, uBound));
+ } else {
+ sourceFinalOperand = sourceLifeline.get().getParentOperand(finalRange.get());
+ targetFinalOperand = targetLifeline.get().getParentOperand(finalRange.get());
+ }
+
+ valid = sourceFinalOperand.get() == targetFinalOperand.get();
+ }
+
+ return valid;
+
+ }
+
+ private static class MoveType {
+ private boolean fromTop;
+
+ private boolean needsCompoundMove;
+
+ public MoveType(boolean needsCompoundMove, boolean fromTop) {
+ this.fromTop = fromTop;
+ this.needsCompoundMove = needsCompoundMove;
+ }
+
+ public boolean isFromTop() {
+ return fromTop;
+ }
+
+ public boolean needsCompoundMove() {
+ return needsCompoundMove;
+ }
+
+ @Override
+ public String toString() {
+ return "[fromTop:" + fromTop + ", compound:" + needsCompoundMove + "]";
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java
new file mode 100644
index 0000000000..6fce46fe4b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+import org.eclipse.sirius.description.tool.NodeCreationDescription;
+import org.eclipse.sirius.diagram.graphical.edit.policies.CreationUtil;
+import org.eclipse.sirius.diagram.graphical.edit.policies.NodeCreationEditPolicy;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.VerticalPositionFunction;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.description.tool.CombinedFragmentCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ExecutionCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InteractionUseCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.ObservationPointCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.OperandCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.StateCreationTool;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.command.SequenceDelegatingCommandFactory;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.StateEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.FrameCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.EditPartsHelper;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutUtils;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+
+/**
+ * A node creation edit policy which invokes the ExecutionCreationTool correctly
+ * (with all the proper variables).
+ *
+ * @author pcdavid
+ */
+public class SequenceNodeCreationPolicy extends NodeCreationEditPolicy {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getCreateCommand(CreateRequest request) {
+ Option<SequenceDiagramEditPart> sdep = shouldRetargetToDiagram(request);
+ if (sdep.some()) {
+ return sdep.get().getCommand(request);
+ }
+ return super.getCreateCommand(request);
+ }
+
+ private Option<SequenceDiagramEditPart> shouldRetargetToDiagram(CreateRequest request) {
+ AbstractToolDescription tool = getTool(request);
+ if (!(getHost() instanceof StateEditPart) && (tool instanceof InteractionUseCreationTool || tool instanceof CombinedFragmentCreationTool)) {
+ /*
+ * If the user is trying to create an IU or CF by clicking on a
+ * lifeline or execution, redirect the request to the diagram, but
+ * note the original target so that the initial coverage can be
+ * computed.
+ */
+ IGraphicalEditPart self = (IGraphicalEditPart) getHost();
+ SequenceDiagramEditPart sdep = EditPartsHelper.getSequenceDiagramPart(self);
+ if (sdep != null) {
+ @SuppressWarnings("unchecked")
+ Map<Object, Object> extData = request.getExtendedData();
+ extData.put(FrameCreationValidator.ORIGINAL_TARGET, getHost());
+ return Options.newSome(sdep);
+ }
+ }
+
+ return Options.newNone();
+ }
+
+ /**
+ * Overridden to show feedback for Execution creation.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void showTargetFeedback(Request request) {
+ if (request instanceof CreateRequest) {
+ Option<SequenceDiagramEditPart> sdep = shouldRetargetToDiagram((CreateRequest) request);
+ if (sdep.some() && sdep.get().getEditPolicy(EditPolicy.CONTAINER_ROLE) != null) {
+ sdep.get().getEditPolicy(EditPolicy.CONTAINER_ROLE).showTargetFeedback(request);
+ }
+ }
+ super.showTargetFeedback(request);
+ }
+
+ /**
+ * Overridden to erase feedback for Execution creation.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void eraseTargetFeedback(Request request) {
+ if (request instanceof CreateRequest) {
+ Option<SequenceDiagramEditPart> sdep = shouldRetargetToDiagram((CreateRequest) request);
+ if (sdep.some() && sdep.get().getEditPolicy(EditPolicy.CONTAINER_ROLE) != null) {
+ sdep.get().getEditPolicy(EditPolicy.CONTAINER_ROLE).eraseTargetFeedback(request);
+ }
+ }
+ super.eraseTargetFeedback(request);
+ }
+
+ /**
+ * Overridden to invoke ExecutionCreationTool correctly.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getCreateNodeOnNodeCommand(CreateRequest request, NodeCreationDescription tool, DNode viewnode) {
+ if (tool instanceof ExecutionCreationTool || tool instanceof StateCreationTool || tool instanceof ObservationPointCreationTool) {
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(getHost());
+ SequenceDDiagram diagram = sequenceDiagram.getSequenceDDiagram();
+
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+ EventEnd startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(diagram, location.y);
+ EventEnd startingEndSuccessor = SequenceGraphicalHelper.getEndAfter(diagram, location.y);
+ if (tool instanceof ExecutionCreationTool) {
+ Point bottomRight = location.getCopy().getTranslated(0, 1);
+ bottomRight = new Point(location.x + 2 * LayoutUtils.SCALE, computeBottomY(diagram, location, startingEndSuccessor));
+ GraphicalHelper.logical2screen(bottomRight, (IGraphicalEditPart) getHost());
+ request.setSize(new Dimension(LayoutConstants.DEFAULT_EXECUTION_WIDTH, LayoutConstants.DEFAULT_EXECUTION_HEIGHT));
+ }
+ CreationUtil creationUtil = new CreationUtil(request, getDiagramCommandFactory(startingEndPredecessor, startingEndPredecessor, location), getRealLocation(request), request.getSize(),
+ getHost());
+ return creationUtil.getNodeCreationCommand(viewnode, tool);
+ } else {
+ return super.getCreateNodeOnNodeCommand(request, tool, viewnode);
+ }
+ }
+
+ /**
+ * Overridden to invoke OperandCreationTool correctly.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getCreateContainerInContainerCommand(CreateRequest request, ContainerCreationDescription tool, DDiagramElementContainer viewNodeContainer) {
+ final Command result;
+ if (isCreatingOperandInCombinedFragment(tool, viewNodeContainer)) {
+ Option<Operand> operand = getOperand(viewNodeContainer);
+ if (operand.some()) {
+ SequenceDiagram sequenceDiagram = EditPartsHelper.getSequenceDiagram(getHost());
+ SequenceDDiagram diagram = sequenceDiagram.getSequenceDDiagram();
+
+ EventEnd startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(diagram, operand.get().getVerticalRange().getUpperBound() - 1);
+
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+
+ CreationUtil creationUtil = new CreationUtil(request, getDiagramCommandFactory(startingEndPredecessor, startingEndPredecessor, location), getRealLocation(request), getHost());
+ result = creationUtil.getContainerCreationDescription((DDiagramElementContainer) viewNodeContainer.eContainer(), tool);
+ } else {
+ result = UnexecutableCommand.INSTANCE;
+ }
+ } else {
+ result = super.getCreateContainerInContainerCommand(request, tool, viewNodeContainer);
+ }
+ return result;
+ }
+
+ private Option<Operand> getOperand(DDiagramElementContainer viewNodeContainer) {
+ Collection<View> views = ISequenceElementAccessor.getViewsForSemanticElement((SequenceDDiagram) viewNodeContainer.getParentDiagram(), viewNodeContainer.getTarget());
+ List<View> operandViews = Lists.newArrayList(Iterables.filter(views, Operand.notationPredicate()));
+ for (View view : operandViews) {
+ Option<Operand> optOperand = ISequenceElementAccessor.getOperand(view);
+ if (optOperand.some()) {
+ return optOperand;
+ }
+ }
+ return Options.newNone();
+ }
+
+ private boolean isCreatingOperandInCombinedFragment(ContainerCreationDescription tool, DDiagramElementContainer viewNodeContainer) {
+ return tool instanceof OperandCreationTool && Operand.viewpointElementPredicate().apply(viewNodeContainer)
+ && CombinedFragment.viewpointElementPredicate().apply((DDiagramElement) viewNodeContainer.eContainer());
+ }
+
+ private int computeBottomY(SequenceDDiagram diagram, Point location, EventEnd startingEndSuccessor) {
+ int nextY;
+ int parentBottomMargin = LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ if (startingEndSuccessor != null) {
+ nextY = new VerticalPositionFunction(diagram).apply(startingEndSuccessor);
+ } else {
+ nextY = location.y + LayoutConstants.DEFAULT_EXECUTION_HEIGHT + parentBottomMargin;
+ }
+ int bottomY = Math.max(location.y + LayoutConstants.DEFAULT_EXECUTION_HEIGHT, nextY - parentBottomMargin);
+ return bottomY;
+ }
+
+ private IDiagramCommandFactory getDiagramCommandFactory(EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor, Point location) {
+ EditPart host = getHost();
+ SequenceDiagram seqDiag = EditPartsHelper.getSequenceDiagram(host);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(seqDiag.getNotationDiagram());
+ final DDiagramEditor diagramEditor = (DDiagramEditor) this.getHost().getViewer().getProperty(DDiagramEditor.EDITOR_ID);
+ if (diagramEditor == null) {
+ return null;
+ }
+ final Object adapter = diagramEditor.getAdapter(IDiagramCommandFactoryProvider.class);
+
+ final IDiagramCommandFactoryProvider cmdFactoryProvider = (IDiagramCommandFactoryProvider) adapter;
+ final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
+ return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor, location);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceSiriusGraphicalNodeEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceSiriusGraphicalNodeEditPolicy.java
new file mode 100644
index 0000000000..74afd67603
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceSiriusGraphicalNodeEditPolicy.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import java.util.Map;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Layer;
+import org.eclipse.draw2d.LayeredPane;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.LayerConstants;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.editpolicies.FeedbackHelper;
+import org.eclipse.gef.requests.CreateConnectionRequest;
+import org.eclipse.gef.requests.ReconnectRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.description.tool.EdgeCreationDescription;
+import org.eclipse.sirius.diagram.business.internal.view.EdgeLayoutData;
+import org.eclipse.sirius.diagram.graphical.edit.policies.SiriusGraphicalNodeEditPolicy;
+import org.eclipse.sirius.diagram.internal.edit.parts.NoteEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.tool.ToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.operation.SequenceEditPartsOperations;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractMessageCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.CreateMessageCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.DefaultMessageCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.DestroyMessageCreationValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceMessagesRouter;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider;
+
+/**
+ * This edit policy is overridden to use our own connection router. This way
+ * during the creation of a message to self, the feedback will just be an edge
+ * between the first click and the pointer, instead of a polyline connected to
+ * the bottom of the source edit part (lifeline).
+ *
+ * @author smonnier
+ *
+ */
+public class SequenceSiriusGraphicalNodeEditPolicy extends SiriusGraphicalNodeEditPolicy {
+
+ /**
+ * Constant used to store the location in draw2d absolute coordinates of the
+ * click on the {@link EdgeTarget} source.
+ */
+ protected static final String DRAW2D_EDGE_LOCATION_SOURCE = "edge.absolute.location.source";
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected FeedbackHelper getFeedbackHelper(CreateConnectionRequest request) {
+ if (feedbackHelper == null) {
+ feedbackHelper = new FeedbackHelper();
+ Point p = request.getLocation();
+ connectionFeedback = createDummyConnection(request);
+ connectionFeedback.setConnectionRouter(new SequenceMessagesRouter());
+ connectionFeedback.setSourceAnchor(getSourceConnectionAnchor(request));
+ feedbackHelper.setConnection(connectionFeedback);
+ addFeedback(connectionFeedback);
+ feedbackHelper.update(null, p);
+ }
+ return feedbackHelper;
+ }
+
+ /**
+ * Overridden to use LayerConstants.SCALED_FEEDBACK_LAYER instead of
+ * LayerConstants.FEEDBACK_LAYER, to have connection creation feedback
+ * scalable with zoom & scroll. If LayerConstants.SCALED_FEEDBACK_LAYER
+ * layer not available, return by default a LayerConstants.FEEDBACK_LAYER
+ * layer.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected IFigure getFeedbackLayer() {
+ IFigure feedbackLayer = null;
+ IFigure scaledLayers = getLayer(LayerConstants.SCALABLE_LAYERS);
+ if (scaledLayers instanceof LayeredPane) {
+ LayeredPane layeredPane = (LayeredPane) scaledLayers;
+ if (scaledLayers != null) {
+ Layer layer = layeredPane.getLayer(LayerConstants.SCALED_FEEDBACK_LAYER);
+ if (layer != null) {
+ feedbackLayer = layer;
+ }
+ }
+ }
+ if (feedbackLayer == null) {
+ feedbackLayer = super.getFeedbackLayer();
+ }
+ return feedbackLayer;
+ }
+
+ /**
+ * Overridden to save the position on the source.
+ *
+ * @param request
+ * the request to create a new connection targeting an
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart}
+ * @return super.getConnectionCreateCommand() using CreateConnectionRequest
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
+ Command connectionCreateCommand = super.getConnectionCreateCommand(request);
+ if (new RequestQuery(request).isSequenceMessageCreation() && request.getLocation() != null && org.eclipse.gef.RequestConstants.REQ_CONNECTION_START.equals(request.getType())) {
+ ISequenceEventEditPart host = (ISequenceEventEditPart) getHost();
+ ISequenceEvent sequenceEvent = host.getISequenceEvent();
+ SequenceDiagram sequenceDiagram = sequenceEvent.getDiagram();
+
+ Point location = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, (IGraphicalEditPart) getHost());
+ request.getExtendedData().put(DRAW2D_EDGE_LOCATION_SOURCE, location.getCopy());
+ EventEnd startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDiagram.getSequenceDDiagram(), location.y);
+ if (!sequenceEvent.canChildOccupy(null, new Range(location.y, location.y)) || ToolCommandBuilder.isStartingEventEndOfCombinedFragment(sequenceDiagram, startingEndPredecessor)) {
+ connectionCreateCommand = UnexecutableCommand.INSTANCE;
+ }
+ }
+ return connectionCreateCommand;
+ }
+
+ /**
+ * Overridden to manage create message creation.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
+ Command result = UnexecutableCommand.INSTANCE;
+ if (request instanceof CreateConnectionViewRequest) {
+ result = super.getConnectionCompleteCommand(request);
+ } else {
+ RequestQuery requestQuery = new RequestQuery(request);
+ if (!requestQuery.isSequenceMessageCreation()) {
+ result = super.getConnectionCompleteCommand(request);
+ } else {
+ ISequenceEventEditPart host = (ISequenceEventEditPart) getHost();
+ ISequenceEvent sequenceEvent = host.getISequenceEvent();
+ SequenceDiagram sequenceDiagram = sequenceEvent.getDiagram();
+
+ EditPart sourceEditPart = request.getSourceEditPart();
+ EditPart targetEditPart = request.getTargetEditPart();
+
+ Option<ISequenceElement> sequenceEventSource = ISequenceElementAccessor.getISequenceElement((View) sourceEditPart.getModel());
+ Option<ISequenceElement> sequenceEventTarget = ISequenceElementAccessor.getISequenceElement((View) targetEditPart.getModel());
+
+ Map<?, ?> extendedData = request.getExtendedData();
+ Point firstClickLocation = (Point) extendedData.get(DRAW2D_EDGE_LOCATION_SOURCE);
+ Point secondClickLocation = request.getLocation().getCopy();
+ GraphicalHelper.screen2logical(secondClickLocation, (IGraphicalEditPart) getHost());
+
+ if (firstClickLocation != null && secondClickLocation != null
+ && !ExecutionSemanticEditPolicy.isCombinedFragmentTitleRangeEdgeCreation(sequenceEvent, sequenceDiagram, firstClickLocation, secondClickLocation)) {
+ AbstractMessageCreationValidator validator = null;
+
+ if (requestQuery.isCreateMessageCreation()) {
+ validator = new CreateMessageCreationValidator();
+ } else if (requestQuery.isDestroyMessageCreation()) {
+ validator = new DestroyMessageCreationValidator();
+ } else {
+ validator = new DefaultMessageCreationValidator();
+ }
+
+ validator.setSource(sequenceEventSource.get());
+ validator.setTarget(sequenceEventTarget.get());
+
+ validator.setFirstClickLocation(firstClickLocation);
+ validator.setSecondClickLocation(secondClickLocation);
+
+ if ((request.getSourceEditPart() instanceof NoteEditPart) || firstClickLocation == null || secondClickLocation == null || validator.isValid(request)) {
+ result = super.getConnectionCompleteCommand(request);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.graphical.edit.policies.SiriusGraphicalNodeEditPolicy#buildCreateEdgeCommand(org.eclipse.gef.requests.CreateConnectionRequest,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.description.tool.EdgeCreationDescription,
+ * org.eclipse.sirius.tools.api.command.IDiagramCommandFactoryProvider,
+ * org.eclipse.sirius.diagram.business.internal.view.EdgeLayoutData)
+ */
+ @Override
+ protected Command buildCreateEdgeCommand(CreateConnectionRequest request, EdgeTarget source, EdgeTarget target, EdgeCreationDescription edgeCreationDescription,
+ IDiagramCommandFactoryProvider cmdFactoryProvider, EdgeLayoutData edgeLayoutData) {
+ CompoundCommand result = new CompoundCommand();
+ IGraphicalEditPart host = (IGraphicalEditPart) getHost();
+ SequenceEditPartsOperations.appendFullRefresh(host, result);
+ addStoreLayoutDataCommand(result, edgeLayoutData);
+ SequenceEditPartsOperations.buildCreateEdgeCommand(host, result, request, source, target, edgeCreationDescription, cmdFactoryProvider);
+ SequenceEditPartsOperations.appendFullRefresh(host, result);
+ return result;
+ }
+
+ /**
+ * Overridden to forbidden explicit source reconnection of Message.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getReconnectSourceCommand(ReconnectRequest request) {
+ Command result = null;
+ if (request.getConnectionEditPart() instanceof SequenceMessageEditPart) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ result = super.getReconnectSourceCommand(request);
+ }
+ return result;
+ }
+
+ /**
+ * Overridden to forbidden explicit target reconnection of Message.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getReconnectTargetCommand(ReconnectRequest request) {
+ Command result = null;
+ if (request.getConnectionEditPart() instanceof SequenceMessageEditPart) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ result = super.getReconnectTargetCommand(request);
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/StateSelectionEditPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/StateSelectionEditPolicy.java
new file mode 100644
index 0000000000..dac0f468a8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/StateSelectionEditPolicy.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.StateEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator.AbstractNodeEventResizeSelectionValidator;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+
+/**
+ * Specialization of the default policy for states, in order to customize resize
+ * command and feedback.
+ *
+ * @author mporhel
+ */
+public class StateSelectionEditPolicy extends ExecutionSelectionEditPolicy {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command getResizeCommand(ChangeBoundsRequest request) {
+ updateHorizontalResize(request);
+ return super.getResizeCommand(request);
+ }
+
+ /*
+ * Feedback
+ */
+ /**
+ * Show/update the horizontal feedback lines aligned on the top and bottom
+ * of the execution.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
+ eraseChangeBoundsFeedback(request);
+
+ StateEditPart hostPart = (StateEditPart) getHost();
+ AbstractNodeEvent host = (AbstractNodeEvent) hostPart.getISequenceEvent();
+ RequestQuery requestQuery = new RequestQuery(request);
+
+ if (requestQuery.isResize()) {
+ updateHorizontalResize(request);
+ customiseFeedbackFigure(request);
+
+ AbstractNodeEventResizeSelectionValidator validator = AbstractNodeEventResizeSelectionValidator.getOrCreateValidator(request, host);
+ validator.validate();
+ showResizeFeedBack(request);
+ feedBack(validator);
+ } else {
+ super.showChangeBoundsFeedback(request);
+ }
+ }
+
+ /**
+ * Customize feedback : State figure is centered regarding the parent
+ * figure. Don't use BorderItemLocator to locate the feedback.
+ *
+ * @param request
+ * current resuqte to feedback.
+ */
+ private void customiseFeedbackFigure(ChangeBoundsRequest request) {
+ final IFigure feedback = getDragSourceFeedbackFigure();
+ final Rectangle rect = getInitialFeedbackBounds().getCopy();
+ getHostFigure().translateToAbsolute(rect);
+ rect.translate(request.getMoveDelta());
+ rect.resize(request.getSizeDelta());
+ getHostFigure().translateToRelative(rect);
+
+ getHostFigure().translateToAbsolute(rect);
+ feedback.translateToRelative(rect);
+ feedback.setBounds(rect);
+ }
+
+ /**
+ * Update the request, to center the horizontal resize.
+ *
+ * @param request
+ * the current request.
+ */
+ private void updateHorizontalResize(ChangeBoundsRequest request) {
+ Point moveDelta = new Point(request.getMoveDelta());
+ Dimension sizeDelta = new Dimension(request.getSizeDelta());
+ RequestQuery requestQuery = new RequestQuery(request);
+
+ if (requestQuery.isResize()) {
+ if (moveDelta.x == 0 && sizeDelta.width != 0) {
+ moveDelta.x = -sizeDelta.width;
+ }
+
+ if (sizeDelta.width == 0 && moveDelta.x != 0) {
+ sizeDelta.width = -moveDelta.x;
+ }
+
+ if (moveDelta.x == -sizeDelta.width) {
+ sizeDelta.width -= moveDelta.x;
+ }
+
+ request.setMoveDelta(moveDelta);
+ request.setSizeDelta(sizeDelta);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/tools/SequenceMessageSelectConnectionEditPartTracker.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/tools/SequenceMessageSelectConnectionEditPartTracker.java
new file mode 100644
index 0000000000..3715cf5431
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/tools/SequenceMessageSelectConnectionEditPartTracker.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.tools;
+
+import java.util.Map;
+
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.DragTracker;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.requests.BendpointRequest;
+import org.eclipse.gmf.runtime.gef.ui.internal.tools.SelectConnectionEditPartTracker;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * Specific connection selection tracker to handle move of messageToSelf
+ * messages.
+ *
+ * @author mporhel
+ *
+ */
+@SuppressWarnings("restriction")
+public class SequenceMessageSelectConnectionEditPartTracker extends SelectConnectionEditPartTracker implements DragTracker {
+
+ private boolean fromTop = true;
+
+ private BendpointRequest bendpointRequest;
+
+ private boolean msgToSelfMove;
+
+ /**
+ * Method SequenceMessageSelectConnectionEditPartTracker.
+ *
+ * @param owner
+ * ConnectionNodeEditPart that creates and owns the tracker
+ * object
+ */
+ public SequenceMessageSelectConnectionEditPartTracker(ConnectionEditPart owner) {
+ super(owner);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Request createSourceRequest() {
+ Request rq = super.createSourceRequest();
+ if (rq instanceof BendpointRequest) {
+ bendpointRequest = (BendpointRequest) rq;
+ }
+ return rq;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void updateSourceRequest() {
+ super.updateSourceRequest();
+ if (bendpointRequest != null) {
+ @SuppressWarnings("unchecked")
+ Map<Object, Object> extData = bendpointRequest.getExtendedData();
+ if (msgToSelfMove) {
+ extData.put(SequenceMessageEditPart.MSG_TO_SELF_TOP_MOVE, fromTop);
+ } else {
+ extData.remove(SequenceMessageEditPart.MSG_TO_SELF_TOP_MOVE);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean handleButtonDown(int button) {
+ boolean res = super.handleButtonDown(button);
+ SequenceMessageEditPart smep = (SequenceMessageEditPart) getSourceEditPart();
+ if (new ISequenceEventQuery(smep.getISequenceEvent()).isReflectiveMessage()) {
+ Range range = smep.getISequenceEvent().getVerticalRange();
+ Point location = getLocation().getCopy();
+ GraphicalHelper.screen2logical(location, smep);
+
+ Connection connection = smep.getConnectionFigure();
+
+ int x = connection.getPoints().getMidpoint().x;
+ if (x == location.x) {
+ msgToSelfMove = false;
+ } else {
+ fromTop = location.y <= range.getLowerBound() || location.y < range.middleValue();
+ msgToSelfMove = true;
+ }
+ }
+ return res;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInstanceRoleValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInstanceRoleValidator.java
new file mode 100644
index 0000000000..05cfc0fc52
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInstanceRoleValidator.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.notation.Bounds;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+
+/**
+ * Abstract class to validate InstanceRole move & resize request and get from it
+ * a command.
+ *
+ * @author edugueperoux
+ *
+ */
+public abstract class AbstractInstanceRoleValidator {
+
+ /**
+ * Common map of future location for instanceRoles in move/resize.
+ */
+ protected Map<InstanceRole, Point> moveDeltas = new HashMap<InstanceRole, Point>();
+
+ /**
+ * Common comparator to have calculated ordering in x coordinate.
+ */
+ protected InstanceRoleGraphicalHorizontalOrderingComparator comparator = new InstanceRoleGraphicalHorizontalOrderingComparator();
+
+ /**
+ * List of instanceRoles in selection of the request.
+ */
+ protected List<InstanceRole> instanceRoles;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSequenceElements(List<InstanceRole> sequenceElements) {
+ this.instanceRoles = sequenceElements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isValid(ChangeBoundsRequest request) {
+ Preconditions.checkNotNull(instanceRoles, "validator must know on which instanceRoles check the request validation");
+
+ return true;
+ }
+
+ /**
+ * Get the index in the instanceRolesToMove left to right ordered list where
+ * to insert the current instanceRole in move at the future location
+ * locationAfterMoving.
+ *
+ * @param locationAfterMoving
+ * the requested location for the instanceRole in move
+ * @param instanceRolesToMove
+ * the instanceRolesToMove left to right ordered list
+ * @return the index in the instanceRolesToMove left to right ordered list
+ * where to insert the current instanceRole in move at the future
+ * location locationAfterMoving
+ */
+ protected int getDropIndex(Point locationAfterMoving, List<InstanceRole> instanceRolesToMove) {
+ ListIterator<InstanceRole> iterator = instanceRolesToMove.listIterator();
+ InstanceRole instanceRoleEditPart;
+ int x = 0;
+ int i = 0;
+ while (iterator.hasNext()) {
+ instanceRoleEditPart = iterator.next();
+ Bounds bounds = (Bounds) instanceRoleEditPart.getNotationNode().getLayoutConstraint();
+ x = bounds.getX();
+ if (moveDeltas != null && moveDeltas.containsKey(instanceRoleEditPart)) {
+ x += moveDeltas.get(instanceRoleEditPart).x;
+ }
+ if (locationAfterMoving.x <= x) {
+ return i;
+ } else {
+ i++;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Test if dropIndex is same as initialIndex.
+ *
+ * @param dropIndex
+ * future index of the instanceRole in move.
+ * @param instanceRole
+ * the instanceRole in move
+ *
+ * @return true if the dropIndex is same as initialIndex
+ */
+ protected boolean dropIndexSameAsInitialIndex(int dropIndex, InstanceRole instanceRole) {
+ List<InstanceRole> allInstanceRoleEditParts = getOrderedMovableInstanceRoles(Collections.<InstanceRole> emptyList());
+ return allInstanceRoleEditParts.indexOf(instanceRole) == dropIndex;
+ }
+
+ /**
+ * Get a left-to-right ordered list of movable InstanceRole.
+ *
+ * @param instanceRoleToMove
+ * the InstanceRole in move
+ *
+ * @return the left-to-right ordered list of movable InstanceRole
+ */
+ protected List<InstanceRole> getOrderedMovableInstanceRoles(List<InstanceRole> instanceRoleToMove) {
+ List<InstanceRole> allInstanceRoles = Lists.newArrayList(instanceRoles.get(0).getDiagram().getAllInstanceRoles());
+ allInstanceRoles.removeAll(instanceRoleToMove);
+ Collections.sort(allInstanceRoles, comparator);
+
+ return allInstanceRoles;
+ }
+
+ /**
+ * Move instanceRoles at the right of the requested location of the
+ * instanceRole in move.
+ *
+ * @param boundsAfterMoving
+ * requested Bounds of InstanceRole in move
+ * @param iteratorForRight
+ * iterator on the left-right ordered list of instanceRoles at
+ * the right of requested location of the instanceRole in move
+ */
+ protected void moveOverLappedAtTheRightForMoving(Rectangle boundsAfterMoving, ListIterator<InstanceRole> iteratorForRight) {
+
+ }
+
+ public Map<InstanceRole, Point> getMoveDeltas() {
+ return moveDeltas;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java
new file mode 100644
index 0000000000..78b7bc69cd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractInteractionFrameValidator.java
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractFrame;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * This class is responsible to check whether a request on an interaction use
+ * should be accepted (i.e. it would produce a well-formed diagram). While doing
+ * the validation, it also stores all the relevant information required to
+ * actually perform the interaction properly.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractInteractionFrameValidator {
+ private static final String FRAME_RESIZE_VALIDATOR = "org.eclipse.sirius.sequence.resize.frame.validator";
+
+ /**
+ * Expansion zone.
+ */
+ protected Range expansionZone = Range.emptyRange();
+
+ /**
+ * Current interaction use or combined fragment.
+ */
+ protected final AbstractFrame frame;
+
+ /**
+ * Final Range of the current interaction use.
+ */
+ protected Range finalRange;
+
+ /**
+ * Initial Range of the current interaction use.
+ */
+ protected Range initialRange;
+
+ /**
+ * The default interaction use/combined fragment height.
+ */
+ protected int defaultFrameHeight;
+
+ /**
+ * Validation status.
+ */
+ protected boolean valid = true;
+
+ /**
+ * Other moved elements.
+ */
+ protected final Set<ISequenceEvent> movedElements = Sets.newHashSet();
+
+ /**
+ * Not in moved elements.
+ */
+ protected final Predicate<ISequenceEvent> unmoved = Predicates.not(Predicates.in(movedElements));
+
+ private boolean initialized;
+
+ private final Collection<Integer> invalidPositions = Lists.newArrayList();
+
+ private Predicate<Object> unMove = Predicates.instanceOf(Lifeline.class);
+
+ private Predicate<Object> invalidParents;
+
+ private Function<ISequenceEvent, Range> futureRangeFunction = new Function<ISequenceEvent, Range>() {
+
+ public Range apply(ISequenceEvent from) {
+ Range range = from.getVerticalRange();
+ if (frame.equals(from)) {
+ range = finalRange;
+ } else if (expansionZone != null && !expansionZone.isEmpty()) {
+ if (range.includes(expansionZone.getLowerBound())) {
+ range = new Range(range.getLowerBound(), range.getUpperBound() + expansionZone.width());
+ } else if (range.getLowerBound() >= expansionZone.getLowerBound()) {
+ range = range.shifted(expansionZone.width());
+ }
+ }
+
+ return range;
+ }
+ };
+
+ /**
+ * Allow to query the request.
+ */
+ private final RequestQuery requestQuery;
+
+ /**
+ * Constructor.
+ *
+ * @param frame
+ * the interaction use or combined fragment which will be
+ * resized.
+ * @param requestQuery
+ * a query on the request targeting the execution.
+ */
+ public AbstractInteractionFrameValidator(AbstractFrame frame, RequestQuery requestQuery) {
+ this.frame = frame;
+ this.requestQuery = requestQuery;
+ this.valid = false;
+
+ this.invalidParents = Predicates.or(Predicates.instanceOf(AbstractFrame.class), Predicates.instanceOf(State.class));
+
+ }
+
+ /**
+ * Return the validation status. Validate the request result in the first
+ * call only.
+ *
+ * @return the validation status.
+ */
+ public final boolean isValid() {
+ if (!initialized) {
+ validate();
+ initialized = true;
+ }
+ return valid;
+ }
+
+ public Range getFinalRange() {
+ return finalRange;
+ }
+
+ /**
+ * Performs all the computations required to validate the resizing, and
+ * stores any important information which will be useful to actually execute
+ * the resize if it is valid, like for example avoid contact with siblings.
+ */
+ protected void validate() {
+ valid = checkAndComputeRanges();
+ if (valid) {
+ Collection<ISequenceEvent> finalParents = getFinalParentsWithAutoExpand();
+
+ Collection<ISequenceEvent> movableParents = Lists.newArrayList(Iterables.filter(finalParents, Predicates.not(unMove)));
+ Collection<ISequenceEvent> fixedParents = Lists.newArrayList(Iterables.filter(finalParents, unMove));
+ if (movableParents.isEmpty() || !movedElements.containsAll(movableParents)) {
+
+ valid = valid && Iterables.isEmpty(Iterables.filter(finalParents, invalidParents));
+ valid = valid && (!Iterables.any(finalParents, Predicates.instanceOf(Operand.class)) || finalParents.size() == 1);
+ valid = valid && checkFinalRangeStrictlyIncludedInParents(movableParents);
+ valid = valid && checkLocalSiblings(movableParents);
+ }
+ valid = valid && checkFinalRangeStrictlyIncludedInParents(fixedParents);
+ valid = valid && checkLocalSiblings(fixedParents);
+ }
+
+ if (getRequestQuery().isResize()) {
+ valid = valid && checkGlobalPositions();
+ }
+ }
+
+ private Collection<ISequenceEvent> getFinalParentsWithAutoExpand() {
+ Collection<ISequenceEvent> finalParentsWithAutoExpand = Lists.newArrayList();
+ Collection<ISequenceEvent> finalParents = getFinalParents();
+ Collection<Lifeline> coveredLifelines = frame.computeCoveredLifelines();
+ for (ISequenceEvent localParent : finalParents) {
+ // check the need of space expansion
+ if (localParent != null) {
+ if (!movedElements.contains(localParent) && !localParent.canChildOccupy(frame, finalRange, Lists.newArrayList(movedElements), coveredLifelines)) {
+ expansionZone = computeExpansionZone();
+ }
+
+ finalParentsWithAutoExpand.add(localParent);
+ }
+ }
+
+ return finalParentsWithAutoExpand;
+ }
+
+ /**
+ * Computes, checks and stores the initial and final range of the
+ * interaction use if the resize is performed.
+ */
+ private boolean checkAndComputeRanges() {
+ // Proper range
+ initialRange = frame.getVerticalRange();
+ Rectangle newBounds = getResizedBounds(new Rectangle(0, initialRange.getLowerBound(), 0, initialRange.width()));
+
+ if (newBounds.height < defaultFrameHeight) {
+ finalRange = initialRange;
+ return false;
+ }
+
+ finalRange = Range.verticalRange(newBounds);
+ return true;
+ }
+
+ /**
+ * Resizing an interaction use can not change which parents it is on, and
+ * can not have any impact on that parents's ranges, so the final range of
+ * the interaction use after the resize must be strictly included in the
+ * ranges of the parents.
+ */
+ private boolean checkFinalRangeStrictlyIncludedInParents(Collection<ISequenceEvent> parentEvents) {
+ boolean checked = true;
+
+ Iterable<ISequenceEvent> unMovedParents = Iterables.filter(parentEvents, unmoved);
+ Iterator<ISequenceEvent> iterator = unMovedParents.iterator();
+ while (checked && iterator.hasNext()) {
+ ISequenceEvent parent = iterator.next();
+ Range parentRange = parent.getVerticalRange();
+
+ if (expansionZone != null && !expansionZone.isEmpty()) {
+ parentRange = new Range(parentRange.getLowerBound(), parentRange.getUpperBound() + expansionZone.width());
+ }
+ /*
+ * We make two tests separately so that is is easier when debugging
+ * to determine which of the conditions went wrong, if any.
+ */
+ boolean interactionInRange = parentRange.includes(finalRange.grown(LayoutConstants.EXECUTION_CHILDREN_MARGIN));
+ checked = checked && interactionInRange;
+ }
+
+ return checked;
+ }
+
+ /**
+ * Get final parents event after application of the current interaction.
+ *
+ * @return final parents.
+ */
+ protected abstract Collection<ISequenceEvent> getFinalParents();
+
+ private boolean checkLocalSiblings(Collection<ISequenceEvent> finalParents) {
+ boolean okForSiblings = true;
+ for (ISequenceEvent localParent : finalParents) {
+ for (ISequenceEvent localSibling : Iterables.filter(localParent.getSubEvents(), unmoved)) {
+ if (frame.equals(localSibling)) {
+ continue;
+ }
+
+ okForSiblings = checkSibling(localSibling);
+ if (!okForSiblings) {
+ break;
+ }
+ }
+ if (!okForSiblings) {
+ break;
+ }
+ }
+ return okForSiblings;
+ }
+
+ private boolean checkSibling(ISequenceEvent sibling) {
+ Range siblingRange = sibling.getVerticalRange();
+
+ if (canExpand()) {
+ if (expansionZone != null && !expansionZone.isEmpty()) {
+ siblingRange = getExpandedRange(siblingRange);
+ } else if (siblingRange.intersects(finalRange)) {
+ expansionZone = computeExpansionZone();
+ siblingRange = getExpandedRange(siblingRange);
+ }
+ // Uncomment to avoid forbidden feedback between resize and resize +
+ // auto-expand
+ // return !siblingRange.intersects(finalRange);
+ }
+ return !siblingRange.intersects(finalRange);
+ }
+
+ private Range getExpandedRange(Range siblingRange) {
+ if (expansionZone != null && !expansionZone.isEmpty() && siblingRange.intersects(expansionZone)) {
+ return siblingRange.shifted(expansionZone.width());
+ }
+ return siblingRange;
+ }
+
+ private Rectangle getResizedBounds(Rectangle bounds) {
+ return getRequestQuery().getLogicalTransformedRectangle(bounds);
+ }
+
+ /**
+ * Get the expansion zone requested to validate the move.
+ *
+ * @return an expansion zone.
+ */
+ public Range getExpansionZone() {
+ return canExpand() && expansionZone != null ? expansionZone : Range.emptyRange();
+ }
+
+ /**
+ * Check that the current validator handles auto-expand.
+ *
+ * @return true if the validator supports the autoexpand.
+ */
+ protected abstract boolean canExpand();
+
+ /**
+ * Compute the allowed expansion zone.
+ *
+ * @return the computed expansion zone.
+ */
+ protected abstract Range computeExpansionZone();
+
+ /**
+ * Other moved elements.
+ *
+ * @param otherMovedElements
+ * the other moved elements.
+ */
+ public void setMovedElements(Collection<ISequenceEvent> otherMovedElements) {
+ if (otherMovedElements != null && !otherMovedElements.isEmpty()) {
+ movedElements.addAll(otherMovedElements);
+ }
+ }
+
+ /**
+ * Get the validator from the request extended data or a new one.
+ *
+ * @param cbr
+ * the current resize request.
+ * @param host
+ * the host execution
+ * @return a validator.
+ */
+ @SuppressWarnings("unchecked")
+ public static AbstractInteractionFrameValidator getOrCreateResizeValidator(ChangeBoundsRequest cbr, AbstractFrame host) {
+ RequestQuery requestQuery = new RequestQuery(cbr);
+ Preconditions.checkArgument(requestQuery.isResize());
+ AbstractInteractionFrameValidator validator = null;
+ Object object = cbr.getExtendedData().get(FRAME_RESIZE_VALIDATOR);
+ if (object instanceof AbstractInteractionFrameValidator) {
+ validator = (AbstractInteractionFrameValidator) object;
+ if (!validator.getRequestQuery().getLogicalDelta().equals(requestQuery.getLogicalDelta())) {
+ validator = null;
+ }
+ }
+
+ if (validator == null && requestQuery.isResize()) {
+ if (host instanceof CombinedFragment) {
+ validator = new CombinedFragmentResizeValidator((CombinedFragment) host, requestQuery);
+ } else if (host instanceof InteractionUse) {
+ validator = new InteractionUseResizeValidator((InteractionUse) host, requestQuery);
+ }
+ cbr.getExtendedData().put(FRAME_RESIZE_VALIDATOR, validator);
+ }
+ return validator;
+ }
+
+ public Collection<Integer> getInvalidPositions() {
+ return invalidPositions;
+ }
+
+ private boolean checkGlobalPositions() {
+ boolean safeMove = true;
+ invalidPositions.addAll(new PositionsChecker(frame.getDiagram(), futureRangeFunction).getInvalidPositions());
+ safeMove = invalidPositions.isEmpty();
+ return safeMove;
+ }
+
+ public RequestQuery getRequestQuery() {
+ return requestQuery;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractMessageCreationValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractMessageCreationValidator.java
new file mode 100644
index 0000000000..0ef196f71c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractMessageCreationValidator.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.requests.CreateConnectionRequest;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+
+/**
+ * Abstract validator to check if a message creation request is valid.
+ *
+ * @author edugueperoux
+ */
+public abstract class AbstractMessageCreationValidator {
+
+ /**
+ * {@link ISequenceElement} source.
+ */
+ protected ISequenceElement sequenceElementSource;
+
+ /**
+ * {@link ISequenceElement} target.
+ */
+ protected ISequenceElement sequenceElementTarget;
+
+ /**
+ * coordinate of the click on the {@link ISequenceElement} source.
+ */
+ protected Point firstClickLocation;
+
+ /**
+ * coordinate of the click on the {@link ISequenceElement} target.
+ */
+ protected Point secondClickLocation;
+
+ /**
+ * Check if a message creation request is valid.
+ *
+ * @param request
+ * the {@link CreateConnectionRequest} of a message creation to
+ * validate
+ *
+ * @return true if request is valid
+ */
+ public boolean isValid(CreateConnectionRequest request) {
+ // Preconditions.checkNotNull(sequenceElementSource,
+ // "validator must know on which ISequenceElement check the request validation");
+ // Preconditions.checkNotNull(sequenceElementTarget,
+ // "validator must know on which ISequenceElement check the request validation");
+ // Preconditions.checkNotNull(firstClickLocation,
+ // "validator must know the click on the first ISequenceElement");
+ // Preconditions.checkNotNull(secondClickLocation,
+ // "validator must know the click on the second ISequenceElement");
+ boolean valid = true;
+
+ valid = valid && sequenceElementSource != null;
+ valid = valid && sequenceElementTarget != null;
+ valid = valid && firstClickLocation != null;
+ valid = valid && secondClickLocation != null;
+
+ return valid;
+ }
+
+ /**
+ * Setter for {@link ISequenceElement} source.
+ *
+ * @param elementSource
+ * the {@link ISequenceElement} source
+ */
+ public void setSource(ISequenceElement elementSource) {
+ this.sequenceElementSource = elementSource;
+ }
+
+ /**
+ * Setter for {@link ISequenceElement} target.
+ *
+ * @param elementTarget
+ * the {@link ISequenceElement} target
+ */
+ public void setTarget(ISequenceElement elementTarget) {
+ this.sequenceElementTarget = elementTarget;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setFirstClickLocation(Point firstClickLocation) {
+ this.firstClickLocation = firstClickLocation;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSecondClickLocation(Point secondClickLocation) {
+ this.secondClickLocation = secondClickLocation;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractNodeEventResizeSelectionValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractNodeEventResizeSelectionValidator.java
new file mode 100644
index 0000000000..fc1cd6f7b7
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractNodeEventResizeSelectionValidator.java
@@ -0,0 +1,491 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.notation.Location;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractFrame;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.FinalParentHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Abstract class to validate Execution move & resize request and get from it a
+ * command.
+ *
+ * @author edugueperoux
+ *
+ */
+public class AbstractNodeEventResizeSelectionValidator {
+
+ /**
+ * Key constant use for request on multiple selection.
+ */
+ public static final String GROUP_REQUEST_ALREADY_ANSWERED = "Already answered";
+
+ private static final String EXECUTION_RESIZE_VALIDATOR = "org.eclipse.sirius.sequence.resize.execution.validator";
+
+ /**
+ * The expansionZine.
+ */
+ protected Range expansionZone;
+
+ /**
+ * The finalParent.
+ */
+ protected ISequenceEvent finalParent;
+
+ /**
+ * Common map of future location for executions in move/resize.
+ */
+ protected Map<AbstractNodeEvent, Location> moveDeltas = new HashMap<AbstractNodeEvent, Location>();
+
+ private boolean valid;
+
+ private AbstractNodeEvent host;
+
+ private ChangeBoundsRequest request;
+
+ private boolean initialized;
+
+ private Collection<Integer> invalidPositions = Lists.newArrayList();
+
+ private RequestQuery requestQuery;
+
+ /**
+ * Constructor.
+ *
+ * @param host
+ * the main execution to resize/move
+ * @param request
+ * the resize request targeting the execution.
+ */
+ protected AbstractNodeEventResizeSelectionValidator(AbstractNodeEvent host, ChangeBoundsRequest request) {
+ this.host = host;
+ this.requestQuery = new RequestQuery(request);
+ Preconditions.checkArgument(requestQuery.isResize());
+ this.request = request;
+ }
+
+ /**
+ * Return the validation status. Validate the request result in the first
+ * call only.
+ *
+ * @return the validation status.
+ */
+ public final boolean isValid() {
+ validate();
+ return valid;
+ }
+
+ /**
+ * Performs all the computations required to validate the resizing, and
+ * stores any important information which will be useful to actually execute
+ * the move if it is valid, like for example avoid contact with siblings or
+ * handle reconnection.
+ */
+ public final void validate() {
+ if (!initialized) {
+ doValidation();
+ initialized = true;
+ }
+ }
+
+ /**
+ * Performs all the computations required to validate the resizing, and
+ * stores any important information which will be useful to actually execute
+ * the resize if it is valid, like for example avoid contact with siblings.
+ */
+ private void doValidation() {
+ Preconditions.checkNotNull(host, "validator must know on which executions check the request validation");
+
+ FinalParentHelper finalParentHelper = new FinalParentHelper(host, requestQuery);
+ finalParentHelper.computeFinalParent();
+ expansionZone = finalParentHelper.getRequiredExpansion();
+ finalParent = finalParentHelper.getFinalParent();
+
+ if (finalParent == null && requestQuery.isResizeFromBottom() && expansionZone != null && expansionZone.width() != 0) {
+ finalParent = host.getParentEvent();
+ }
+
+ valid = validateNewBoundsForAllTargets() && finalParent != null;
+ valid = valid && checkGlobalPositions();
+ }
+
+ /**
+ * Verifies whether the new position/size of the execution would still be
+ * valid if we accept the request. In particular, ensures sibling events can
+ * not overlap.
+ *
+ * @return true if the request is validated to true
+ */
+ protected boolean validateNewBoundsForAllTargets() {
+ return Iterables.all(Iterables.filter(request.getEditParts(), ExecutionEditPart.class), new Predicate<ExecutionEditPart>() {
+ public boolean apply(ExecutionEditPart input) {
+ return validateNewBounds(input);
+ }
+ });
+ }
+
+ /**
+ * Checks whether the new bounds implied by the requested change are valid
+ * for this execution. Uses Draw2D information to get the current bounds.
+ */
+ private boolean validateNewBounds(ExecutionEditPart self) {
+ final boolean result;
+ Rectangle bounds = self.getFigure().getBounds().getCopy();
+ Rectangle newBounds = requestQuery.getFinalBounds(self);
+ ISequenceEvent selfEvent = self.getISequenceEvent();
+ ISequenceEvent parent = selfEvent.getParentEvent();
+ boolean newBoundsFails = (newBounds.width <= 0 && bounds.width != 0) || newBounds.height <= 0;
+ if (newBoundsFails || parent == null) {
+ result = false;
+ } else {
+ boolean isMove = requestQuery.isMove();
+ /*
+ * If this is a MOVE, children will move along with us, so it is OK
+ * for them. Otherwise this is a RESIZE, where children do not move,
+ * so the resize is constrained by the range currently occupied by
+ * them.
+ */
+ boolean okForChildren = isMove || Range.verticalRange(newBounds).includes(self.getISequenceEvent().getOccupiedRange());
+ // linkedMessages are moved during execution resize too
+ // boolean okForLinkedMessages = isMove ||
+ // validateMessageToSelfMinRanges(self, request,
+ // GraphicalHelper.verticalRange(bounds),
+ // GraphicalHelper.verticalRange(newBounds));
+ boolean okForParent = ((AbstractNodeEvent) self.getISequenceEvent()).getLifeline().get().getValidSubEventsRange().includes(Range.verticalRange(newBounds));
+ /*
+ * Do not allow resize to expand beyond the range of the parent.
+ */
+ if (requestQuery.isResize()) {
+ if (!parent.getVerticalRange().includes(Range.verticalRange(newBounds))) {
+ okForParent = false;
+ }
+ }
+ /*
+ * Also check that the messages which will move with us will not
+ * become inconsistent.
+ */
+ boolean okForMessageEnds = (expansionZone != null) || validateMessageEndsConsistency(self, bounds, newBounds);
+ result = okForChildren && okForParent && okForMessageEnds;
+ }
+ return result;
+ }
+
+ /**
+ * If this execution is delimited by a start and finish message, make sure
+ * they always point to the same remote execution/lifeline.
+ *
+ * @param move
+ * indicates the current action : move or resize.
+ */
+ private boolean validateMessageEndsConsistency(ExecutionEditPart self, Rectangle bounds, Rectangle newBounds) {
+ boolean result = true;
+ AbstractNodeEvent abstractNodeEvent = (AbstractNodeEvent) self.getISequenceEvent();
+ List<Message> delimitingMessages = Lists.newArrayList(Iterables.filter(EventEndHelper.getCompoundEvents(self.getISequenceEvent()), Message.class));
+ if (delimitingMessages.size() == 2) {
+ Message callMessage = delimitingMessages.get(0);
+ Message returnMessage = delimitingMessages.get(1);
+
+ Range oldRange = Range.verticalRange(bounds);
+ Range newRange = Range.verticalRange(newBounds);
+ int deltaYStart = newRange.getLowerBound() - oldRange.getLowerBound();
+ int deltaYFinish = newRange.getUpperBound() - oldRange.getUpperBound();
+ int deltaHStart = 0;
+ int deltaHFinish = 0;
+
+ if (requestQuery.isDirectedByMessage()) {
+ if (requestQuery.isResizeFromTop() && callMessage.isReflective()) {
+ deltaHStart = deltaYStart;
+ deltaYStart = 0;
+ }
+
+ if (requestQuery.isResizeFromBottom() && returnMessage.isReflective()) {
+ deltaHFinish = -deltaYFinish;
+ }
+ }
+
+ ISequenceEvent startMessageRemote = FinalParentHelper.getFinalRemoteParent(abstractNodeEvent, delimitingMessages.get(0), deltaYStart, deltaHStart);
+ ISequenceEvent finishMessageRemote = FinalParentHelper.getFinalRemoteParent(abstractNodeEvent, delimitingMessages.get(1), deltaYFinish, deltaHFinish);
+ result = startMessageRemote == finishMessageRemote;
+
+ if (!result && requestQuery.isResizeFromBottom() && finishMessageRemote != null) {
+ Range verticalRange = finishMessageRemote.getVerticalRange();
+ if (newRange.getLowerBound() < verticalRange.getLowerBound()) {
+ Range errorRange = new Range(verticalRange.getLowerBound() - 1, newRange.getUpperBound());
+ expansionZone = expansionZone == null ? errorRange : errorRange.union(expansionZone);
+ result = true;
+ }
+ }
+
+ result = result && respectLowRangeMarginOfParent(startMessageRemote, callMessage, newRange) && respectUpperRangeMarginOfParent(startMessageRemote, returnMessage, newRange);
+
+ } else if (delimitingMessages.size() == 1) {
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(self.getISequenceEvent());
+ SingleEventEnd delimitedSee = getDelimitedSingleEventEnd(self, ends);
+
+ Range oldRange = Range.verticalRange(bounds);
+ Range newRange = Range.verticalRange(newBounds);
+ int deltaYStart = newRange.getLowerBound() - oldRange.getLowerBound();
+ int deltaYFinish = newRange.getUpperBound() - oldRange.getUpperBound();
+
+ int delimitedDeltaY = 0;
+ int delimitedDeltaH = 0;
+ if (delimitedSee != null) {
+ delimitedDeltaY = delimitedSee.isStart() ? deltaYStart : deltaYFinish;
+
+ if (requestQuery.isDirectedByMessage()) {
+ Message msg = delimitingMessages.get(0);
+ if (delimitedSee.isStart() && requestQuery.isResizeFromTop() && msg.isReflective()) {
+ delimitedDeltaH = delimitedDeltaY;
+ delimitedDeltaY = 0;
+ }
+
+ if (!delimitedSee.isStart() && requestQuery.isResizeFromBottom() && msg.isReflective()) {
+ delimitedDeltaH = -delimitedDeltaY;
+ }
+ }
+ }
+
+
+
+
+ ISequenceEvent prevMessageRemote = FinalParentHelper.getFinalRemoteParent(abstractNodeEvent, delimitingMessages.get(0), 0, 0);
+ ISequenceEvent delimitingMessageRemote = FinalParentHelper.getFinalRemoteParent(abstractNodeEvent, delimitingMessages.get(0), delimitedDeltaY, delimitedDeltaH);
+ result = prevMessageRemote == delimitingMessageRemote;
+
+ // prevMessageRemote == delimitingMessageRemote
+ Message callMessage = delimitingMessages.get(0);
+ result = result && respectLowRangeMarginOfParent(prevMessageRemote, callMessage, newRange);
+
+ }
+ return result;
+ }
+
+ /**
+ * Check upper range margin between parentSequenceEventEditPart and
+ * returnMessageEditPart respect LayoutConstants.EXECUTION_CHILDREN_MARGIN
+ * margin
+ *
+ * @param parentSequenceEventEditPart
+ * @param returnMessageEditPart
+ * @param newRange
+ *
+ * @return
+ */
+ private boolean respectUpperRangeMarginOfParent(ISequenceEvent parentSequenceEvent, Message returnMessage, Range newRange) {
+ boolean upperRangeMarginOK = true;
+ if (parentSequenceEvent != null) {
+ Range remoteParentRange = parentSequenceEvent.getVerticalRange();
+ Range finishMessageRange = returnMessage.getVerticalRange();
+ if (requestQuery.isDirectedByMessage() && requestQuery.isResizeFromBottom() && returnMessage.isReflective()) {
+ finishMessageRange = new Range(finishMessageRange.getLowerBound() + requestQuery.getLogicalDelta().height, finishMessageRange.getUpperBound());
+ }
+ int upperRangeMargin = Math.abs(remoteParentRange.getUpperBound() - (newRange.getUpperBound() + finishMessageRange.width()));
+ upperRangeMarginOK = upperRangeMargin >= LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ }
+ return upperRangeMarginOK;
+ }
+
+ /**
+ * Check if lower range margin between parentSequenceEventEditPart and
+ * callMessageEditPart respect LayoutConstants.EXECUTION_CHILDREN_MARGIN
+ * margin
+ *
+ * @param parentSequenceEventEditPart
+ * @param callMessageEditPart
+ * @param newRange
+ * @return
+ */
+ private boolean respectLowRangeMarginOfParent(ISequenceEvent parentSequenceEvent, Message callMessage, Range newRange) {
+ boolean lowerRangeMarginOK = true;
+ if (parentSequenceEvent != null) {
+ Range remoteParentRange = parentSequenceEvent.getVerticalRange();
+ Range startMessageRange = callMessage.getVerticalRange();
+
+ int lowerRangeMargin = Math.abs((newRange.getLowerBound() - startMessageRange.width()) - remoteParentRange.getLowerBound());
+ lowerRangeMarginOK = lowerRangeMargin >= LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ }
+ return lowerRangeMarginOK;
+ }
+
+ private SingleEventEnd getDelimitedSingleEventEnd(ExecutionEditPart self, List<EventEnd> ends) {
+ Iterable<CompoundEventEnd> thisDelimitedEnds = Iterables.filter(ends, CompoundEventEnd.class);
+ if (!Iterables.isEmpty(thisDelimitedEnds)) {
+ return EventEndHelper.getSingleEventEnd(thisDelimitedEnds.iterator().next(), self.resolveTargetSemanticElement());
+ }
+ return null;
+ }
+
+ public Range getExpansionZone() {
+ return expansionZone;
+ }
+
+ public void setExpansionZone(Range expansionZone) {
+ this.expansionZone = expansionZone;
+ }
+
+ /**
+ * Return the final hierarchical parent.
+ *
+ * @return the final hierarchical parent.
+ */
+ public ISequenceEvent getFinalHierarchicalParent() {
+ return getReconnectionFinalParent(finalParent);
+ }
+
+ private ISequenceEvent getReconnectionFinalParent(ISequenceEvent ise) {
+ if (ise instanceof Operand) {
+ return getReconnectionFinalParent(((Operand) ise).getCombinedFragment());
+ }
+
+ ISequenceEvent reconnectionParent = ise;
+ if (ise instanceof AbstractFrame) {
+ AbstractFrame frame = (AbstractFrame) ise;
+ Collection<ISequenceEvent> computeParentEvents = frame.computeParentEvents(Collections.singletonList(host.getLifeline().get()));
+ ISequenceEvent iSequenceEvent = Iterables.get(computeParentEvents, 0);
+
+ if (iSequenceEvent instanceof Lifeline || iSequenceEvent instanceof AbstractNodeEvent) {
+ reconnectionParent = iSequenceEvent;
+ } else if (ise != null) {
+ reconnectionParent = getReconnectionFinalParent(iSequenceEvent);
+ }
+ }
+ return reconnectionParent;
+ }
+
+ public void setFinalParent(ISequenceEvent finalParent) {
+ this.finalParent = finalParent;
+ }
+
+ /**
+ * Get the validator from the request extended data or a new one.
+ *
+ * @param cbr
+ * the current request.
+ * @param host
+ * the host execution
+ * @return a validator.
+ */
+ @SuppressWarnings("unchecked")
+ public static AbstractNodeEventResizeSelectionValidator getOrCreateValidator(ChangeBoundsRequest cbr, AbstractNodeEvent host) {
+ RequestQuery requestQuery = new RequestQuery(cbr);
+ AbstractNodeEventResizeSelectionValidator validator = null;
+ Object object = cbr.getExtendedData().get(EXECUTION_RESIZE_VALIDATOR);
+ if (object instanceof AbstractNodeEventResizeSelectionValidator) {
+ validator = (AbstractNodeEventResizeSelectionValidator) object;
+ if (!validator.getRequestQuery().getLogicalDelta().equals(requestQuery.getLogicalDelta())) {
+ validator = null;
+ }
+ }
+
+ if (validator == null && requestQuery.isResize()) {
+ validator = new AbstractNodeEventResizeSelectionValidator(host, cbr);
+ cbr.getExtendedData().put(EXECUTION_RESIZE_VALIDATOR, validator);
+ }
+ return validator;
+ }
+
+ private RequestQuery getRequestQuery() {
+ return requestQuery;
+ }
+
+ public Collection<Integer> getInvalidPositions() {
+ return invalidPositions;
+ }
+
+ private boolean checkGlobalPositions() {
+ boolean safeMove = true;
+ final Option<Message> startMessage;
+ final Option<Message> endMessage;
+
+ if (host instanceof Execution) {
+ Execution exec = (Execution) host;
+ startMessage = exec.getStartMessage();
+ endMessage = exec.getEndMessage();
+ } else {
+ startMessage = Options.newNone();
+ endMessage = Options.newNone();
+ }
+
+ Range actualRange = host.getVerticalRange();
+ Rectangle newBounds = requestQuery.getLogicalTransformedRectangle(new Rectangle(0, actualRange.getLowerBound(), 0, actualRange.width()));
+ if (newBounds.height < 0) {
+ safeMove = false;
+ } else {
+ final Range finalRange = Range.verticalRange(newBounds);
+ Function<ISequenceEvent, Range> futureRangeFunction = new Function<ISequenceEvent, Range>() {
+
+ public Range apply(ISequenceEvent from) {
+ Range verticalRange = from.getVerticalRange();
+ if (host.equals(from)) {
+ verticalRange = finalRange;
+ } else if (startMessage.some() && startMessage.get().equals(from)) {
+ if (!startMessage.get().isReflective()) {
+ verticalRange = new Range(finalRange.getLowerBound(), finalRange.getLowerBound());
+ } else if (requestQuery.isResizeFromTop()) {
+ if (requestQuery.isDirectedByMessage()) {
+ verticalRange = new Range(verticalRange.getLowerBound(), verticalRange.getUpperBound() + requestQuery.getLogicalDelta().y);
+ } else {
+ // reflexive and resized -> moved message
+ verticalRange = verticalRange.shifted(requestQuery.getLogicalDelta().y);
+ }
+ }
+ } else if (endMessage.some() && endMessage.get().equals(from)) {
+ if (!endMessage.get().isReflective()) {
+ verticalRange = new Range(finalRange.getUpperBound(), finalRange.getUpperBound());
+ } else if (requestQuery.isResizeFromBottom()) {
+ if (requestQuery.isDirectedByMessage()) {
+ verticalRange = new Range(verticalRange.getLowerBound() + requestQuery.getLogicalDelta().height, verticalRange.getUpperBound());
+ } else { // reflexive and resized -> moved message
+ verticalRange = verticalRange.shifted(requestQuery.getLogicalDelta().height);
+ }
+ }
+ }
+
+ return verticalRange;
+ }
+ };
+ invalidPositions.addAll(new PositionsChecker(host.getDiagram(), futureRangeFunction).getInvalidPositions());
+ safeMove = invalidPositions.isEmpty();
+ }
+ return safeMove;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java
new file mode 100644
index 0000000000..cf4acedfec
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractOperandValidator.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * This class is responsible to check whether a request on an operand should be
+ * accepted (i.e. it would produce a well-formed diagram). While doing the
+ * validation, it also stores all the relevant information required to actually
+ * perform the interaction properly.
+ *
+ * @author smonnier
+ */
+public abstract class AbstractOperandValidator {
+
+ /**
+ * Allow to query the request.
+ */
+ protected final RequestQuery requestQuery;
+
+ /**
+ * Current Operand.
+ */
+ protected final Operand currentOperand;
+
+ /**
+ * Sibling Operand that will have the opposite resize.
+ */
+ protected Option<Operand> siblingOperandOption = Options.newNone();
+
+ private Range initialOperandRange;
+
+ private Range finalOperandRange;
+
+ private Range initialSiblingOperandRange;
+
+ private Range finalSiblingOperandRange;
+
+ private boolean valid;
+
+ /**
+ * Constructor.
+ *
+ * @param operand
+ * the Operand which will be resized.
+ * @param requestQuery
+ * a query on the resize request targeting the execution.
+ */
+ public AbstractOperandValidator(Operand operand, RequestQuery requestQuery) {
+ this.currentOperand = operand;
+ this.requestQuery = requestQuery;
+ this.valid = false;
+
+ if (requestQuery.isResizeFromTop()) {
+ siblingOperandOption = operand.getPreviousOperand();
+ } else if (requestQuery.isResizeFromBottom()) {
+ siblingOperandOption = operand.getFollowingOperand();
+ }
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public Range getFinalRange() {
+ return finalOperandRange;
+ }
+
+ /**
+ * Performs all the computations required to validate the resizing, and
+ * stores any important information which will be useful to actually execute
+ * the resize if it is valid, like for example avoid contact with siblings.
+ */
+ public void validate() {
+ valid = checkAndComputeRanges();
+
+ valid = valid && checkContainedISequenceEvent();
+ }
+
+ /**
+ * Computes, checks and stores the initial and final range of the operand if
+ * the resize is performed.
+ */
+ private boolean checkAndComputeRanges() {
+ boolean result = true;
+ // Proper range
+ initialOperandRange = currentOperand.getVerticalRange();
+ Rectangle newBounds = getResizedBounds(new Rectangle(0, initialOperandRange.getLowerBound(), 0, initialOperandRange.width()));
+
+ if (newBounds.height < LayoutConstants.DEFAULT_OPERAND_HEIGHT) {
+ result = false;
+ } else {
+ // The current operand new range is valid, we can check the sibling
+ // operand
+ if (siblingOperandOption.some()) {
+ Operand siblingOperand = siblingOperandOption.get();
+ initialSiblingOperandRange = siblingOperand.getVerticalRange();
+ Rectangle siblingOperandNewBounds = getInverseResizedBounds(new Rectangle(0, initialSiblingOperandRange.getLowerBound(), 0, initialSiblingOperandRange.width()));
+ if (siblingOperandNewBounds.height < LayoutConstants.DEFAULT_OPERAND_HEIGHT) {
+ result = false;
+ } else {
+ // The minimum heights are validated, we can save the final
+ // ranges
+ finalSiblingOperandRange = Range.verticalRange(siblingOperandNewBounds);
+ }
+ }
+ finalOperandRange = Range.verticalRange(newBounds);
+ }
+ return result;
+ }
+
+ private boolean checkContainedISequenceEvent() {
+ boolean result = finalOperandRange.includes(currentOperand.getOccupiedRange().grown(LayoutConstants.EXECUTION_CHILDREN_MARGIN));
+ if (siblingOperandOption.some()) {
+ result = result && finalSiblingOperandRange.includes(siblingOperandOption.get().getOccupiedRange().grown(LayoutConstants.EXECUTION_CHILDREN_MARGIN));
+ }
+ return result;
+ }
+
+ private Rectangle getResizedBounds(Rectangle bounds) {
+ return requestQuery.getLogicalTransformedRectangle(bounds);
+ }
+
+ private Rectangle getInverseResizedBounds(Rectangle bounds) {
+ Rectangle logicalDelta = requestQuery.getLogicalDelta();
+ Point moveDelta = new Point();
+ Dimension sizeDelta = logicalDelta.getSize().getCopy().getNegated();
+ if (requestQuery.isResizeFromBottom()) {
+ Dimension size = logicalDelta.getSize().getCopy();
+ moveDelta = new Point(size.width, size.height);
+ }
+ return bounds.getCopy().translate(moveDelta).resize(sizeDelta);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractSequenceInteractionValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractSequenceInteractionValidator.java
new file mode 100644
index 0000000000..9e68de823c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/AbstractSequenceInteractionValidator.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.common.base.Function;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Abstract validator providing common services for user interactions.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractSequenceInteractionValidator {
+
+ /** Keep the value of the validation. */
+ protected boolean valid = true;
+
+ /** {@link RequestQuery} for the current Request. */
+ protected final RequestQuery request;
+
+ /** The expansionZine. */
+ protected Range expansionZone = Range.emptyRange();
+
+ /** {@link ISequenceEvent} in errors. */
+ protected final Set<ISequenceEvent> eventInError = new HashSet<ISequenceEvent>();
+
+ /** invalid positions. */
+ protected final Set<Integer> invalidPositions = new HashSet<Integer>();
+
+ /** invalid ranges. */
+ protected final Set<Range> invalidRanges = new HashSet<Range>();
+
+ /** {@link ISequenceEvent}s moved. */
+ protected final Collection<ISequenceEvent> movedElements = new ArrayList<ISequenceEvent>();
+
+ /** {@link ISequenceEvent}s moved. */
+ protected final Collection<Range> createdElements = new ArrayList<Range>();
+
+ /** startReflexiveMessageToResize. */
+ protected final Collection<Message> startReflexiveMessageToResize = new HashSet<Message>();
+
+ /** endReflexiveMessageToResize. */
+ protected final Collection<Message> endReflexiveMessageToResize = new HashSet<Message>();
+
+ private boolean initialized;
+
+ /**
+ * Constructor.
+ *
+ * @param request
+ * a request query
+ */
+ public AbstractSequenceInteractionValidator(RequestQuery request) {
+ this.request = request;
+ }
+
+ /**
+ * Get the {@link SequenceDiagram}.
+ *
+ * @return the {@link SequenceDiagram}
+ */
+ public abstract SequenceDiagram getDiagram();
+
+ /**
+ * Get the {@link Function} which give the {@link Range} of a
+ * {@link ISequenceEvent}.
+ *
+ * @return the {@link Range} of a {@link ISequenceEvent}
+ */
+ public abstract Function<ISequenceEvent, Range> getRangeFunction();
+
+ /**
+ * Do the validation of the request.
+ */
+ protected abstract void doValidation();
+
+ /**
+ * Return the validation status. Validate the request result in the first
+ * call only.
+ *
+ * @return the validation status.
+ */
+ public final boolean isValid() {
+ validate();
+ return valid;
+ }
+
+ /**
+ * Performs all the computations required to validate the resizing, and
+ * stores any important information which will be useful to actually execute
+ * the move if it is valid, like for example avoid contact with siblings or
+ * handle reconnection.
+ */
+ public final void validate() {
+ if (!initialized) {
+ doValidation();
+ initialized = true;
+ }
+ }
+
+ public Collection<ISequenceEvent> getMovedElements() {
+ return movedElements;
+ }
+
+ public Collection<Range> getCreatedElements() {
+ return createdElements;
+ }
+
+ public Collection<Message> getResizedStartMessages() {
+ return startReflexiveMessageToResize;
+ }
+
+ public Collection<Message> getResizedEndMessages() {
+ return endReflexiveMessageToResize;
+ }
+
+ public Range getExpansionZone() {
+ return expansionZone;
+ }
+
+ public Collection<ISequenceEvent> getEventsInError() {
+ return eventInError;
+ }
+
+ public Collection<Integer> getInvalidPostions() {
+ return invalidPositions;
+ }
+
+ public Collection<Range> getInvalidRanges() {
+ return invalidRanges;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentMoveValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentMoveValidator.java
new file mode 100644
index 0000000000..62d0093aac
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentMoveValidator.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * This class is responsible to check whether a resize request on a Combined
+ * Fragment should be accepted (i.e. it would produce a well-formed diagram).
+ * While doing the validation, it also stores all the relevant information
+ * required to actually perform the resize properly.
+ *
+ * @author smonnier
+ */
+public class CombinedFragmentMoveValidator extends AbstractInteractionFrameValidator {
+
+ /**
+ * Constructor.
+ *
+ * @param combinedFragment
+ * the CombinedFragment which will be moved.
+ * @param requestQuery
+ * a query on the move request targeting the CombinedFragment.
+ */
+ public CombinedFragmentMoveValidator(CombinedFragment combinedFragment, RequestQuery requestQuery) {
+ super(combinedFragment, requestQuery);
+ Preconditions.checkArgument(requestQuery.isMove());
+ defaultFrameHeight = LayoutConstants.DEFAULT_COMBINED_FRAGMENT_HEIGHT;
+ }
+
+ /**
+ * Overridden to get final parents.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceEvent> getFinalParents() {
+ // Possibility to handle "reparent" and insertion"
+ Collection<ISequenceEvent> finalParents = Sets.newLinkedHashSet();
+ Range insertionPoint = new Range(finalRange.getLowerBound(), finalRange.getLowerBound());
+ Collection<Lifeline> coveredLifelines = frame.computeCoveredLifelines();
+ for (Lifeline lifeline : coveredLifelines) {
+ EventFinder finder = new EventFinder(lifeline);
+ finder.setEventsToIgnore(Predicates.in(Collections.<ISequenceEvent> singletonList(frame)));
+ ISequenceEvent localParent = finder.findMostSpecificEvent(insertionPoint);
+ if (localParent != null) {
+ finalParents.add(localParent);
+ }
+ }
+ return finalParents;
+ }
+
+ /**
+ * Auto-expand is allowed for moves.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean canExpand() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Range computeExpansionZone() {
+ Range expansionZone = Range.emptyRange();
+ if (getRequestQuery().isMove()) { // getLogicalDelta().y > 0) {
+ expansionZone = finalRange;
+ }
+ return expansionZone;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentResizeValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentResizeValidator.java
new file mode 100644
index 0000000000..e6af566134
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CombinedFragmentResizeValidator.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * This class is responsible to check whether a resize request on a Combined
+ * Fragment should be accepted (i.e. it would produce a well-formed diagram).
+ * While doing the validation, it also stores all the relevant information
+ * required to actually perform the resize properly.
+ *
+ * @author smonnier
+ */
+public class CombinedFragmentResizeValidator extends AbstractInteractionFrameValidator {
+
+ /**
+ * The impacted Operand on Combined Fragment resize.
+ */
+ private Operand impactedOperand;
+
+ /**
+ * The validator of the impacted Operand.
+ */
+ private OperandResizeValidator impactedOperandResizeValidator;
+
+ /**
+ * Constructor.
+ *
+ * @param combinedFragment
+ * the CombinedFragment which will be resized.
+ * @param requestQuery
+ * a query on the resize request targeting the CombinedFragment.
+ */
+ protected CombinedFragmentResizeValidator(CombinedFragment combinedFragment, RequestQuery requestQuery) {
+ super(combinedFragment, requestQuery);
+ Preconditions.checkArgument(requestQuery.isResizeFromTop() || requestQuery.isResizeFromBottom());
+ defaultFrameHeight = LayoutConstants.DEFAULT_COMBINED_FRAGMENT_HEIGHT;
+ if (requestQuery.isResizeFromTop()) {
+ impactedOperand = combinedFragment.getFirstOperand();
+ } else if (requestQuery.isResizeFromBottom()) {
+ impactedOperand = combinedFragment.getLastOperand();
+ }
+ // A combined fragment always have at least one operand
+ Preconditions.checkArgument(impactedOperand != null);
+ impactedOperandResizeValidator = new OperandResizeValidator(impactedOperand, requestQuery);
+ }
+
+ @Override
+ protected Collection<ISequenceEvent> getFinalParents() {
+ return frame.computeParentEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to trigger the impacted operand resize validation.
+ */
+ @Override
+ protected void validate() {
+ super.validate();
+ if (!(getRequestQuery().isResizeFromBottom() && getRequestQuery().getLogicalDelta().height > 0)) {
+ impactedOperandResizeValidator.validate();
+ valid = valid && impactedOperandResizeValidator.isValid();
+ }
+ }
+
+ /**
+ * Resize do not autorize auto expand.
+ *
+ * @return false;
+ */
+ @Override
+ protected boolean canExpand() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Range computeExpansionZone() {
+ Range expansionZone = Range.emptyRange();
+ if (getRequestQuery().isResizeFromBottom() && getRequestQuery().getLogicalDelta().height > 0) {
+ expansionZone = new Range(initialRange.getUpperBound(), finalRange.getUpperBound());
+ }
+ return expansionZone;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CreateMessageCreationValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CreateMessageCreationValidator.java
new file mode 100644
index 0000000000..18befe38f1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/CreateMessageCreationValidator.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import org.eclipse.gef.requests.CreateConnectionRequest;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceDiagramQuery;
+
+/**
+ * Validator to check if a create message creation request is valid.
+ *
+ * @author edugueperoux
+ */
+public class CreateMessageCreationValidator extends DefaultMessageCreationValidator {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isValid(CreateConnectionRequest request) {
+ boolean valid = super.isValid(request);
+
+ valid = valid && !sequenceElementSource.equals(sequenceElementTarget);
+ // the following is checked by a EdgeCreationDescriptionQuery in
+ // super.getConnectionCreateCommand()
+ // valid = valid && (sequenceElementTarget instanceof Lifeline ||
+ // sequenceElementTarget instanceof InstanceRole);
+ valid = valid && !sequenceElementTarget.getLifeline().get().isExplicitlyCreated();
+
+ valid = valid && checkNotEventAtLowerTimeInSameLifeline();
+
+ return valid;
+ }
+
+ /**
+ * Check that there is not {@link ISequenceEvent} on the target lifeline
+ * with range's lowerbound lower than the firstClickLocation.y .
+ *
+ * @return true if not {@link ISequenceEvent} lower than
+ * firstClickLocation.y
+ */
+ private boolean checkNotEventAtLowerTimeInSameLifeline() {
+ boolean valid = true;
+
+ SequenceDiagram sequenceDiagram = sequenceElementSource.getDiagram();
+ SequenceDiagramQuery sequenceDiagramQuery = new SequenceDiagramQuery(sequenceDiagram);
+ for (ISequenceEvent sequenceEvent : Iterables.filter(sequenceDiagramQuery.getAllSequenceEventsLowerThan(firstClickLocation.y), Predicates.not(Predicates.instanceOf(Lifeline.class)))) {
+ if (isSequenceEventOfLifeline(sequenceEvent, sequenceElementTarget.getLifeline()) || isMessageTargeting(sequenceEvent, sequenceElementTarget.getLifeline())
+ || isCreateMessageFor(sequenceEvent, sequenceElementTarget.getLifeline().get().getInstanceRole())) {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DefaultMessageCreationValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DefaultMessageCreationValidator.java
new file mode 100644
index 0000000000..c3d6fb4fb4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DefaultMessageCreationValidator.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import org.eclipse.gef.requests.CreateConnectionRequest;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceDiagramQuery;
+
+/**
+ * Default validator to check if a message creation request is valid.
+ *
+ * @author edugueperoux
+ */
+public class DefaultMessageCreationValidator extends AbstractMessageCreationValidator {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isValid(CreateConnectionRequest request) {
+ boolean valid = super.isValid(request);
+ valid = valid && validateNotCreatingMessageOnState() && validateNotCreatingMessageInInteractionUse() && validateNotCreatingMessageInDifferentOperands();
+ valid = valid && checkTargetLifelineNotExplicitlyCreatedAtUpperTime() && checkTargetLifelineNotExplicitlyDestroyedAtLowerTime();
+ return valid;
+ }
+
+ private boolean checkTargetLifelineNotExplicitlyCreatedAtUpperTime() {
+ boolean valid = true;
+
+ SequenceDiagram sequenceDiagram = sequenceElementSource.getDiagram();
+ SequenceDiagramQuery sequenceDiagramQuery = new SequenceDiagramQuery(sequenceDiagram);
+ for (ISequenceEvent sequenceEvent : Iterables.filter(sequenceDiagramQuery.getAllSequenceEventsUpperThan(firstClickLocation.y), Predicates.not(Predicates.instanceOf(Lifeline.class)))) {
+ if (isCreateMessageFor(sequenceEvent, sequenceElementTarget.getLifeline().get().getInstanceRole())) {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ }
+
+ private boolean checkTargetLifelineNotExplicitlyDestroyedAtLowerTime() {
+ boolean valid = true;
+
+ SequenceDiagram sequenceDiagram = sequenceElementSource.getDiagram();
+ SequenceDiagramQuery sequenceDiagramQuery = new SequenceDiagramQuery(sequenceDiagram);
+
+ for (ISequenceEvent sequenceEvent : Iterables.filter(sequenceDiagramQuery.getAllSequenceEventsLowerThan(firstClickLocation.y), Predicates.not(Predicates.instanceOf(Lifeline.class)))) {
+ if (isDestroyMessageFor(sequenceEvent, sequenceElementTarget.getLifeline().get().getInstanceRole())) {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ }
+
+ /**
+ * Check if the sequenceEvent is a {@link ISequenceEvent} of lifelineTarget.
+ *
+ * @param sequenceEvent
+ * the {@link ISequenceEvent} to check
+ *
+ * @param lifelineTarget
+ * the probable parent (direct or indirect) of sequenceEvent
+ *
+ * @return true if sequenceEvent is a {@link ISequenceEvent} of
+ * lifelineTarget
+ */
+ protected boolean isSequenceEventOfLifeline(ISequenceEvent sequenceEvent, Option<Lifeline> lifelineTarget) {
+ Option<Lifeline> lifeline = sequenceEvent.getLifeline();
+ if (sequenceEvent instanceof Message) {
+ lifeline = ((Message) sequenceEvent).getSourceElement().getLifeline();
+ }
+ return lifeline.equals(lifelineTarget);
+ }
+
+ /**
+ * Check if sequenceEvent is a message targeting (directly or indirectly)
+ * lifelineTarget.
+ *
+ * @param sequenceEvent
+ * the {@link ISequenceEvent} to check
+ * @param lifelineTarget
+ * the probable target (direct or indirect) of sequenceEvent
+ *
+ * @return true if sequenceEvent is a {@link Message} targeting (directly or
+ * indirectly) lifelineTarget
+ */
+ protected boolean isMessageTargeting(ISequenceEvent sequenceEvent, Option<Lifeline> lifelineTarget) {
+ boolean result = false;
+ if (sequenceEvent instanceof Message) {
+ Message message = (Message) sequenceEvent;
+ result = message.getTargetElement().getLifeline().equals(lifelineTarget);
+ }
+ return result;
+ }
+
+ /**
+ * Validates that a message is not created between two elements that are not
+ * in the same operand.
+ *
+ * @return the validation that a message is not created between two elements
+ * that are not in the same operand.
+ */
+ private boolean validateNotCreatingMessageInDifferentOperands() {
+ boolean result = true;
+
+ Option<Operand> sourceParentOperand = null;
+ if (sequenceElementSource instanceof Lifeline) {
+ sourceParentOperand = ((Lifeline) sequenceElementSource).getParentOperand(secondClickLocation.y);
+ } else if (sequenceElementSource instanceof AbstractNodeEvent) {
+ sourceParentOperand = ((AbstractNodeEvent) sequenceElementSource).getParentOperand(secondClickLocation.y);
+ } else if (sequenceElementSource instanceof ISequenceEvent) {
+ sourceParentOperand = ((ISequenceEvent) sequenceElementSource).getParentOperand();
+ } else if (sequenceElementSource instanceof InstanceRole) {
+ sourceParentOperand = ((InstanceRole) sequenceElementSource).getLifeline().get().getParentOperand(secondClickLocation.y);
+ }
+
+ Option<Operand> targetParentOperand = null;
+ if (sequenceElementTarget instanceof Lifeline) {
+ targetParentOperand = ((Lifeline) sequenceElementTarget).getParentOperand(secondClickLocation.y);
+ } else if (sequenceElementTarget instanceof AbstractNodeEvent) {
+ targetParentOperand = ((AbstractNodeEvent) sequenceElementTarget).getParentOperand(secondClickLocation.y);
+ } else if (sequenceElementTarget instanceof ISequenceEvent) {
+ targetParentOperand = ((ISequenceEvent) sequenceElementTarget).getParentOperand();
+ } else if (sequenceElementTarget instanceof InstanceRole) {
+ targetParentOperand = ((InstanceRole) sequenceElementTarget).getLifeline().get().getParentOperand(secondClickLocation.y);
+ }
+
+ if (targetParentOperand != null && sourceParentOperand != null) {
+ result = targetParentOperand.equals(sourceParentOperand);
+ }
+ return result;
+ }
+
+ /**
+ * Validates that a message is not created inside an interaction use.
+ *
+ * @return the validation that a message is not created inside an
+ * interaction use.
+ */
+ private boolean validateNotCreatingMessageOnState() {
+ boolean result = true;
+ Option<Lifeline> lifelineOption = sequenceElementTarget.getLifeline();
+
+ if (!lifelineOption.some()) {
+ result = false;
+ } else {
+ Lifeline lifeline = lifelineOption.get();
+ for (State state : lifeline.getDiagram().getAllStates()) {
+ if (state.getLifeline().get().equals(lifeline) && state.getVerticalRange().includes(firstClickLocation.y)) {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validates that a message is not created inside an interaction use.
+ *
+ * @return the validation that a message is not created inside an
+ * interaction use.
+ */
+ private boolean validateNotCreatingMessageInInteractionUse() {
+ Option<Lifeline> lifeline = sequenceElementTarget.getLifeline();
+
+ Predicate<InteractionUse> interactionUseOnRealTargetLocation = new Predicate<InteractionUse>() {
+ // Filters interaction use at the vertical position of the
+ // source but on the targeted lifeline.
+ public boolean apply(InteractionUse input) {
+ return input.getVerticalRange().includes(firstClickLocation.y);
+ }
+ };
+
+ return lifeline.some() && !Iterables.any(lifeline.get().getAllCoveringInteractionUses(), interactionUseOnRealTargetLocation);
+ }
+
+ /**
+ * Check if sequenceEvent is a create message of createdInstanceRole.
+ *
+ * @param sequenceEvent
+ * the {@link ISequenceEvent} to check
+ *
+ * @param createdInstanceRole
+ * the probably {@link InstanceRole} created by sequenceEvent
+ *
+ * @return true if createdInstanceRole is well created by the sequenceEvent
+ */
+ protected boolean isCreateMessageFor(ISequenceEvent sequenceEvent, InstanceRole createdInstanceRole) {
+ boolean result = false;
+ if (sequenceEvent instanceof Message) {
+ Message createMessage = (Message) sequenceEvent;
+ result = createMessage.getKind() == Message.Kind.CREATION && createMessage.getTargetElement().equals(createdInstanceRole);
+ }
+ return result;
+ }
+
+ /**
+ * Check if sequenceEvent is a destroy message of destroyedInstanceRole.
+ *
+ * @param sequenceEvent
+ * the {@link ISequenceEvent} to check
+ *
+ * @param destroyedInstanceRole
+ * the probably {@link InstanceRole} destroyed by sequenceEvent
+ *
+ * @return true if destroyedInstanceRole is well destroyed by the
+ * sequenceEvent
+ */
+ protected boolean isDestroyMessageFor(ISequenceEvent sequenceEvent, InstanceRole destroyedInstanceRole) {
+ boolean result = false;
+ if (sequenceEvent instanceof Message) {
+ Message createMessage = (Message) sequenceEvent;
+ result = createMessage.getKind() == Message.Kind.DESTRUCTION;
+ if (createMessage.getTargetElement() instanceof EndOfLife) {
+ EndOfLife endOfLife = (EndOfLife) createMessage.getTargetElement();
+ result = endOfLife.getLifeline().get().getInstanceRole().equals(destroyedInstanceRole);
+ } else {
+ result = false;
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DestroyMessageCreationValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DestroyMessageCreationValidator.java
new file mode 100644
index 0000000000..35b9432c53
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/DestroyMessageCreationValidator.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import org.eclipse.gef.requests.CreateConnectionRequest;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceDiagramQuery;
+
+/**
+ * Validator to check if a destroy message creation request is valid.
+ *
+ * @author edugueperoux
+ */
+public class DestroyMessageCreationValidator extends DefaultMessageCreationValidator {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isValid(CreateConnectionRequest request) {
+ boolean valid = super.isValid(request);
+
+ valid = valid && !sequenceElementTarget.getLifeline().get().isExplicitlyDestroyed();
+ valid = valid && checkNotEventAtUpperTimeInSameLifeline();
+
+ return valid;
+ }
+
+ /**
+ * Check that there is not {@link ISequenceEvent} on the target lifeline
+ * with range's upperbound upper than the firstClickLocation.y .
+ *
+ * @return true if not {@link ISequenceEvent} upper than
+ * firstClickLocation.y
+ */
+ private boolean checkNotEventAtUpperTimeInSameLifeline() {
+ boolean valid = true;
+
+ SequenceDiagram sequenceDiagram = sequenceElementSource.getDiagram();
+ SequenceDiagramQuery sequenceDiagramQuery = new SequenceDiagramQuery(sequenceDiagram);
+
+ for (ISequenceEvent sequenceEvent : Iterables.filter(sequenceDiagramQuery.getAllSequenceEventsUpperThan(firstClickLocation.y), Predicates.not(Predicates.instanceOf(Lifeline.class)))) {
+ if (isSequenceEventOfLifeline(sequenceEvent, sequenceElementTarget.getLifeline()) || isMessageTargeting(sequenceEvent, sequenceElementTarget.getLifeline())
+ || isDestroyMessageFor(sequenceEvent, sequenceElementTarget.getLifeline().get().getInstanceRole())) {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/FrameCreationValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/FrameCreationValidator.java
new file mode 100644
index 0000000000..48bc5b3fd2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/FrameCreationValidator.java
@@ -0,0 +1,493 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractFrame;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.RangeComparator;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ReversedRangeComparator;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceDiagramQuery;
+import org.eclipse.sirius.diagram.sequence.description.tool.CombinedFragmentCreationTool;
+import org.eclipse.sirius.diagram.sequence.description.tool.InteractionUseCreationTool;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceGraphicalHelper;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.CreateRequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Validates that is request for InteractionUse or CombinedFragment is allowed.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class FrameCreationValidator extends AbstractSequenceInteractionValidator {
+
+ /**
+ * The key used in request's extended data map to identify the original
+ * target edit part of a request which was redirected to us.
+ */
+ public static final String ORIGINAL_TARGET = "original.target";
+
+ private static final String VALIDATOR = "org.eclipse.sirius.sequence.frame.creation.validator";
+
+ private SequenceDiagram sequenceDiagram;
+
+ private SequenceDiagramQuery sequenceDiagramQuery;
+
+ private Collection<Lifeline> coverage;
+
+ private EventEnd startingEndPredecessor;
+
+ private EventEnd finishingEndPredecessor;
+
+ private Multimap<Lifeline, ISequenceEvent> sequenceEventsInCreationRange;
+
+ // Store for each lifeline, the first detected event in conflict ->
+ // expansion zone potential start
+ private Set<ISequenceEvent> eventsToShift;
+
+ // Store for each lifeline, the event which should carry the frame to create
+ private Set<ISequenceEvent> localParents;
+
+ private final ContainerCreationDescription ccdTool;
+
+ private Rectangle creationBounds;
+
+ /**
+ * Default constructor to validate InteractionUse or CombinedFragment
+ * creation.
+ *
+ * @param sequenceDiagram
+ * the {@link SequenceDiagram} on which do the creation
+ * @param ccdTool
+ * {@link ContainerCreationDescription}
+ * @param createRequestQuery
+ * {@link CreateRequestQuery}
+ */
+ public FrameCreationValidator(SequenceDiagram sequenceDiagram, ContainerCreationDescription ccdTool, CreateRequestQuery createRequestQuery) {
+ super(createRequestQuery);
+ this.creationBounds = createRequestQuery.getLogicalDelta();
+ this.sequenceDiagram = sequenceDiagram;
+ this.ccdTool = ccdTool;
+ this.sequenceDiagramQuery = new SequenceDiagramQuery(sequenceDiagram);
+ this.sequenceEventsInCreationRange = HashMultimap.create();
+ this.eventsToShift = Sets.newTreeSet(new RangeComparator());
+ this.localParents = Sets.newHashSet();
+ }
+
+ @Override
+ public SequenceDiagram getDiagram() {
+ return sequenceDiagram;
+ }
+
+ @Override
+ public Function<ISequenceEvent, Range> getRangeFunction() {
+ return ISequenceEvent.VERTICAL_RANGE;
+ }
+
+ /**
+ * Validate the creation of a InteractionUse or CombinedFragment creation.
+ */
+ protected void doValidation() {
+ int firstClickY = creationBounds.y;
+ int secondClickY = creationBounds.bottom();
+ Range creationRange = new Range(firstClickY, secondClickY);
+
+ computeCoverage();
+
+ // Potential creation ?
+ if (!coverage.isEmpty() || creationBounds.width > 0 || creationBounds.height > 0) {
+ // Remove tests to always display horizontal guides for two click
+ // creation, (retarget show target feedback in
+ // ExecutionAwareNodeCreationPolicy).
+ createdElements.add(creationRange);
+ }
+
+ valid = !coverage.isEmpty();
+
+ if (valid) {
+ valid = categorizeOverlappedEvents(creationRange);
+ if (valid) {
+ computeExpanzionZone(creationRange);
+ }
+ computeSemanticPredecessors(firstClickY);
+ }
+ }
+
+ private void computeExpanzionZone(Range creationRange) {
+ if (ccdTool instanceof InteractionUseCreationTool) {
+ for (ISequenceEvent parent : localParents) {
+ Range newExpansionZone = new Range(parent.getVerticalRange().getUpperBound() - 1, creationRange.getUpperBound());
+ expansionZone = expansionZone.union(newExpansionZone);
+ }
+
+ SortedSet<ISequenceEvent> overlapped = Sets.newTreeSet(new RangeComparator());
+ overlapped.addAll(sequenceEventsInCreationRange.values());
+ for (ISequenceEvent ise : Iterables.filter(overlapped, Predicates.not(Predicates.in(localParents)))) {
+ if (ise.getVerticalRange().getLowerBound() >= creationRange.getLowerBound()) {
+ Range newExpansionZone = new Range(ise.getVerticalRange().getLowerBound() - 1, creationRange.getUpperBound());
+ expansionZone = expansionZone.union(newExpansionZone);
+ break;
+ }
+ }
+ } else if (ccdTool instanceof CombinedFragmentCreationTool) {
+ Collection<ISequenceEvent> partialOverlaps = Lists.newArrayList(Iterables.concat(localParents, eventsToShift));
+ for (ISequenceEvent parent : localParents) {
+ checkOtherLifelines(parent, partialOverlaps);
+ int expansionCut = Math.max(creationRange.getLowerBound(), parent.getVerticalRange().getUpperBound() - 1);
+ Range newExpansionZone = new Range(expansionCut, creationRange.getUpperBound());
+ expansionZone = expansionZone.union(newExpansionZone);
+ }
+
+ for (ISequenceEvent eventToShift : eventsToShift) {
+ checkOtherLifelines(eventToShift, partialOverlaps);
+ int expansionCut = Math.max(creationRange.getLowerBound(), eventToShift.getVerticalRange().getLowerBound() - 1);
+ Range newExpansionZone = new Range(expansionCut, creationRange.getUpperBound());
+ expansionZone = expansionZone.union(newExpansionZone);
+ }
+ }
+ }
+
+ private void computeSemanticPredecessors(int firstClickY) {
+ // Look for correct finishing end predecessor
+ SequenceDDiagram sequenceDDiagram = sequenceDiagram.getSequenceDDiagram();
+ startingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDDiagram, firstClickY - 1);
+ if (expansionZone != null && !expansionZone.isEmpty()) {
+ finishingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDDiagram, expansionZone.getLowerBound());
+ } else {
+ finishingEndPredecessor = SequenceGraphicalHelper.getEndBefore(sequenceDDiagram, creationBounds.getBottom().y);
+ }
+ }
+
+ private void checkOtherLifelines(ISequenceEvent eventToCheck, Collection<ISequenceEvent> eventsToIgnore) {
+ Range rangeToCheck = eventToCheck.getVerticalRange();
+ for (Lifeline lifeline : sequenceEventsInCreationRange.keySet()) {
+ Collection<ISequenceEvent> overlap = sequenceEventsInCreationRange.get(lifeline);
+ // Dot check event to shift lifeline
+ if (!overlap.contains(eventToCheck)) {
+ for (ISequenceEvent otherLifelineEvent : Iterables.filter(overlap, Predicates.not(Predicates.in(eventsToIgnore)))) {
+ Range otherRange = otherLifelineEvent.getVerticalRange();
+ Range intersection = otherRange.intersection(rangeToCheck);
+ if (!intersection.equals(rangeToCheck) && !intersection.equals(otherRange) && !intersection.isEmpty()) {
+ valid = false;
+ }
+ }
+ }
+ }
+ }
+
+ private void computeCoverage() {
+ coverage = Sets.newLinkedHashSet();
+
+ Set<Lifeline> graphicallyCoveredLifelines = sequenceDiagram.getGraphicallyCoveredLifelines(creationBounds);
+ Object originalTarget = request.getExtendedData().get(ORIGINAL_TARGET);
+ if (originalTarget instanceof ISequenceEventEditPart) {
+ ISequenceEventEditPart sequenceEventEditPart = (ISequenceEventEditPart) originalTarget;
+ Lifeline lifeline = sequenceEventEditPart.getISequenceEvent().getLifeline().get();
+ request.getExtendedData().remove(ORIGINAL_TARGET);
+ coverage.add(lifeline);
+ } else {
+ for (Lifeline coveredLifeline : computeGraphicalCoverageFromSelectionArea(graphicallyCoveredLifelines)) {
+ coverage.add(coveredLifeline);
+ }
+
+ // Remove covered interaction uses
+ for (InteractionUse iu : sequenceDiagram.getAllInteractionUses()) {
+ if (iu.getVerticalRange().includes(creationBounds.y)) {
+ Collection<Lifeline> iuLifelines = iu.computeCoveredLifelines();
+ coverage.removeAll(iuLifelines);
+ // Do not add to events in error, sometimes lifelines cannot
+ // be clearly layouted and ordered
+ }
+ }
+ }
+ }
+
+ private boolean categorizeOverlappedEvents(Range creationRange) {
+ Set<ISequenceEvent> checkedSequenceEvents = Sets.newHashSet();
+ for (Lifeline lifeline : coverage) {
+ categorizeOverlappedEvents(lifeline, creationRange, checkedSequenceEvents);
+ }
+ return eventInError.isEmpty();
+ }
+
+ /**
+ * Checks if the specified inclusion range overlap partially
+ * {@link ISequenceEvent} of the specified {@link Lifeline} vertically (for
+ * Execution, ...) or horizontally (for {@link Message} or
+ * {@link AbstractFrame}).
+ *
+ * @param lifeline
+ * the {@link Lifeline} to check
+ * @param creationRange
+ * the request future range of the AbstractFrame to create
+ */
+ private void categorizeOverlappedEvents(Lifeline lifeline, Range creationRange, Collection<ISequenceEvent> alreadyChecked) {
+
+ SortedSet<ISequenceEvent> overlappedEvents = sequenceDiagramQuery.getAllSequenceEventsOnLifelineOnRange(lifeline, creationRange);
+
+ if (!overlappedEvents.isEmpty()) {
+ this.sequenceEventsInCreationRange.putAll(lifeline, overlappedEvents);
+
+ // Check vertical overlap : Check only the first event 's lower
+ // bound and the last event 's upper bound : other are between those
+ // elements and are completely graphically included
+
+ // Look for potential parent to expand (event which will carry the
+ // created event on the current lifeline)
+ ISequenceEvent lFirstIseInRange = overlappedEvents.first();
+ for (ISequenceEvent ise : overlappedEvents) {
+ if (ise.getVerticalRange().getLowerBound() < creationRange.getLowerBound()) {
+ lFirstIseInRange = ise;
+ } // else complete overlap
+ }
+
+ // Look for potential following sibling to shift.
+ SortedSet<ISequenceEvent> upperBoundSorted = Sets.newTreeSet(new ReversedRangeComparator());
+ upperBoundSorted.addAll(overlappedEvents);
+ ISequenceEvent lLastIseInRange = upperBoundSorted.last();
+
+ // If we have the last sequenceEvent only partially covered we mark
+ // it as to be shifted
+ if (!creationRange.includes(lFirstIseInRange.getVerticalRange().getLowerBound())) {
+ localParents.add(lFirstIseInRange);
+
+ if (ccdTool instanceof InteractionUseCreationTool && lFirstIseInRange instanceof InteractionUse) {
+ eventInError.add(lFirstIseInRange);
+ }
+ }
+ if (!creationRange.includes(lLastIseInRange.getVerticalRange().getUpperBound())) {
+ eventsToShift.add(lLastIseInRange);
+ }
+
+ if (ccdTool instanceof CombinedFragmentCreationTool) {
+
+ categorizeCombinedFragmentOverlappedEvents(creationRange, alreadyChecked, overlappedEvents, lFirstIseInRange);
+ }
+ } else {
+ // Check no conflict with interaction use
+ }
+ }
+
+ private void categorizeCombinedFragmentOverlappedEvents(Range creationRange, Collection<ISequenceEvent> alreadyChecked, SortedSet<ISequenceEvent> overlappedEvents, ISequenceEvent lFirstIseInRange) {
+ // Check horizontal overlap.
+ for (Message message : Iterables.filter(overlappedEvents, Message.class)) {
+ if (!alreadyChecked.contains(message)) {
+ alreadyChecked.add(message);
+ Option<Lifeline> srcLifeline = message.getSourceLifeline();
+ if (srcLifeline.some() && !coverage.contains(srcLifeline.get())) {
+ // As we have coverage incompatibility we do
+ // insertion then we shift all events in the
+ // creationRange
+
+ ISequenceEvent parentEvent = null;
+ ISequenceNode targetElement = message.getTargetElement();
+
+ if (targetElement instanceof ISequenceEvent) {
+ parentEvent = getHigherAncestorWithLowerBoundInCreationRange((ISequenceEvent) targetElement, creationRange);
+ }
+
+ if (parentEvent == null) {
+ eventsToShift.add(lFirstIseInRange);
+ } else if (!creationRange.includes(parentEvent.getVerticalRange())) {
+ eventsToShift.add(message);
+ } else {
+ eventsToShift.add(parentEvent);
+ }
+
+ // eventInError.add(message) : will cause error and
+ // red feedback, expansion is better
+ }
+
+ Option<Lifeline> tgtLifeline = message.getTargetLifeline();
+ if (tgtLifeline.some() && !coverage.contains(tgtLifeline.get())) {
+ // As we have coverage incompatibility we do
+ // insertion then we shift all events in the
+ // creationRange
+ ISequenceEvent parentEvent = null;
+ ISequenceNode sourceElement = message.getSourceElement();
+
+ if (sourceElement instanceof ISequenceEvent) {
+ parentEvent = getHigherAncestorWithLowerBoundInCreationRange((ISequenceEvent) sourceElement, creationRange);
+ }
+
+ if (parentEvent == null) {
+ eventsToShift.add(lFirstIseInRange);
+ } else if (!creationRange.includes(parentEvent.getVerticalRange())) {
+ eventsToShift.add(message);
+ } else {
+ eventsToShift.add(parentEvent);
+ }
+
+ // eventInError.add(message) : will cause error and
+ // red feedback, expansion is better
+ }
+ }
+ }
+
+ for (AbstractFrame frame : Iterables.filter(overlappedEvents, AbstractFrame.class)) {
+ if (!alreadyChecked.contains(frame)) {
+ alreadyChecked.add(frame);
+ Collection<Lifeline> coveredLifelines = frame.computeCoveredLifelines();
+ if (!coverage.containsAll(coveredLifelines) && !eventsToShift.contains(frame) && creationRange.includes(frame.getVerticalRange().getLowerBound())) {
+ eventsToShift.add(frame);
+ // eventInError.add(message) : will cause error and
+ // red feedback, expansion is better
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * @param event
+ * @param creationRange
+ * @return
+ */
+ private ISequenceEvent getHigherAncestorWithLowerBoundInCreationRange(ISequenceEvent event, Range creationRange) {
+ ISequenceEvent parentEvent = event == null ? null : event.getParentEvent();
+ if (parentEvent != null && creationRange.includes(parentEvent.getVerticalRange().getLowerBound())) {
+ return getHigherAncestorWithLowerBoundInCreationRange(parentEvent, creationRange);
+ } else {
+ return event;
+ }
+ }
+
+ private Set<Lifeline> computeGraphicalCoverageFromSelectionArea(Set<Lifeline> graphicallyCoveredLifelines) {
+ Set<Lifeline> validCoverage = new LinkedHashSet<Lifeline>();
+
+ for (Lifeline lifeline : graphicallyCoveredLifelines) {
+ if (coveredByDeepestOperand(lifeline, graphicallyCoveredLifelines)) {
+ validCoverage.add(lifeline);
+ }
+ }
+ return validCoverage;
+ }
+
+ private boolean coveredByDeepestOperand(Lifeline lifeline, Set<Lifeline> graphicallyCoveredLifelines) {
+ boolean coveredByDeepestOperand = true;
+ Range inclusionRange = Range.verticalRange(creationBounds);
+ Option<Operand> findDeepestCoveringOperand = findDeepestCoveringOperand(graphicallyCoveredLifelines);
+ if (findDeepestCoveringOperand.some()) {
+ Option<Operand> parentOperand = lifeline.getParentOperand(inclusionRange);
+ coveredByDeepestOperand = parentOperand.some() && findDeepestCoveringOperand.get().equals(parentOperand.get());
+ }
+ return coveredByDeepestOperand;
+ }
+
+ /**
+ * Finds the deepest operand covering at least one of the lifelines on range
+ * of rect.
+ *
+ * @param graphicallyCoveredLifelines
+ * the covered lifelines
+ * @return the deepest operand covering at least one of the lifelines on
+ * range of rect.
+ */
+ private Option<Operand> findDeepestCoveringOperand(Set<Lifeline> graphicallyCoveredLifelines) {
+ Option<Operand> deepestOperandOption = Options.newNone();
+ for (Lifeline lifeline : graphicallyCoveredLifelines) {
+ // get the operand option for the current lifeline
+ Option<Operand> currentOperandOption = lifeline.getParentOperand(Range.verticalRange(creationBounds));
+ if (deepestOperandOption.some() && currentOperandOption.some()) {
+ // save the deepest operand
+ Operand deepestOperand = deepestOperandOption.get();
+ Operand currentOperand = currentOperandOption.get();
+
+ if (deepestOperand.getVerticalRange().includes(currentOperand.getVerticalRange())) {
+ deepestOperand = currentOperand;
+ }
+ } else if (!deepestOperandOption.some() && currentOperandOption.some()) {
+ // initialize the deepest operand;
+ deepestOperandOption = currentOperandOption;
+ }
+ }
+ return deepestOperandOption;
+ }
+
+ public List<EObject> getCoverage() {
+ return Lists.newArrayList(Iterables.transform(coverage, ISequenceElement.SEMANTIC_TARGET));
+ }
+
+ public Rectangle getCreationBounds() {
+ return creationBounds;
+ }
+
+ public EventEnd getStartingEndPredecessor() {
+ return startingEndPredecessor;
+ }
+
+ public EventEnd getFinishingEndPredecessor() {
+ return finishingEndPredecessor;
+ }
+
+ /**
+ * Get the validator from the request extended data or a new one.
+ *
+ *
+ * @param sequenceDiagram
+ * the {@link SequenceDiagram}
+ * @param containerCreationDescription
+ * {@link ContainerCreationDescription}
+ *
+ * @param createRequestQuery
+ * a query on the current request.
+ *
+ * @return a validator {@link FrameCreationValidator}
+ */
+ @SuppressWarnings("unchecked")
+ public static FrameCreationValidator getOrCreateValidator(SequenceDiagram sequenceDiagram, ContainerCreationDescription containerCreationDescription, CreateRequestQuery createRequestQuery) {
+ FrameCreationValidator validator = null;
+ Object object = createRequestQuery.getExtendedData().get(VALIDATOR);
+
+ if (object instanceof FrameCreationValidator) {
+ validator = (FrameCreationValidator) object;
+ if (validator.request == null || !validator.getCreationBounds().equals(createRequestQuery.getLogicalDelta())) {
+ validator = null;
+ }
+ }
+
+ if (validator == null || createRequestQuery.getExtendedData().get(ORIGINAL_TARGET) != null) {
+ validator = new FrameCreationValidator(sequenceDiagram, containerCreationDescription, createRequestQuery);
+ createRequestQuery.getExtendedData().put(VALIDATOR, validator);
+ }
+ return validator;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/ISEComplexMoveValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/ISEComplexMoveValidator.java
new file mode 100644
index 0000000000..053cd26ca6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/ISEComplexMoveValidator.java
@@ -0,0 +1,633 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractFrame;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ISequenceElementSwitch;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ParentOperandFinder;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Abstract class to validate Execution move & resize request and get from it a
+ * command.
+ *
+ * @author mporhel
+ *
+ */
+public class ISEComplexMoveValidator extends AbstractSequenceInteractionValidator {
+
+ private static final String VALIDATOR = "org.eclipse.sirius.sequence.move.validator";
+
+ /** List of top levels events of the current move. */
+ protected final Set<ISequenceEvent> topLevelElements = new HashSet<ISequenceEvent>();
+
+ /** List of entry points events of the current move (selection). */
+ protected final Set<ISequenceEvent> otherEntryPoints = new HashSet<ISequenceEvent>();
+
+ /** The global moved range. */
+ protected Range globalMovedRange = Range.emptyRange();
+
+ /** The primary selected {@link ISequenceEvent}. */
+ protected ISequenceEvent primarySelected;
+
+ private final int vMove;
+
+ private LinkedHashSet<ISequenceNode> sequenceNodesToMove = Sets.newLinkedHashSet();
+
+ private Collection<Message> messagesToMove = Sets.newLinkedHashSet();
+
+ private Function<ISequenceEvent, Range> rangeFunction = new Function<ISequenceEvent, Range>() {
+
+ public Range apply(ISequenceEvent from) {
+ Range range = from.getVerticalRange();
+ if (movedElements.contains(from)) {
+ range = range.shifted(vMove);
+ } else if (startReflexiveMessageToResize.contains(from)) {
+ int minExecStart = Math.max(range.getLowerBound(), range.getUpperBound() + vMove);
+ range = new Range(range.getLowerBound(), minExecStart);
+ } else if (endReflexiveMessageToResize.contains(from)) {
+ int maxExecEnd = Math.min(range.getUpperBound(), range.getLowerBound() + vMove);
+ range = new Range(maxExecEnd, range.getUpperBound());
+ if (expansionZone != null && !expansionZone.isEmpty() && range.includes(expansionZone.getUpperBound())) {
+ range = new Range(range.getLowerBound(), range.getUpperBound() + expansionZone.width());
+ }
+ } else if (expansionZone != null && !expansionZone.isEmpty()) {
+ if (range.includes(expansionZone.getLowerBound())) {
+ range = new Range(range.getLowerBound(), range.getUpperBound() + expansionZone.width());
+ } else if (range.getLowerBound() >= expansionZone.getLowerBound()) {
+ range = range.shifted(expansionZone.width());
+ }
+ }
+
+ return range;
+ }
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param host
+ * the main execution to resize/move
+ * @param request
+ * the resize request targeting the execution.
+ */
+ protected ISEComplexMoveValidator(ISequenceEvent host, RequestQuery request) {
+ super(request);
+ this.primarySelected = host;
+ Preconditions.checkArgument(request.isMove());
+ this.vMove = request.getLogicalDelta().y;
+ }
+
+ public Function<ISequenceEvent, Range> getRangeFunction() {
+ return rangeFunction;
+ }
+
+ public SequenceDiagram getDiagram() {
+ return primarySelected.getDiagram();
+ }
+
+ public Range getMovedRange() {
+ return globalMovedRange;
+ }
+
+ /**
+ * Return the nodes to move.
+ *
+ * @return a linked hash set of nodes to move.
+ */
+ public LinkedHashSet<ISequenceNode> getSequenceNodeToMove() {
+ return sequenceNodesToMove;
+ }
+
+ public Set<ISequenceEvent> getTopLevelElements() {
+ return topLevelElements;
+ }
+
+ /**
+ * Get the message to move.
+ *
+ * @return the message to move.
+ */
+ public Collection<Message> getMessageToMove() {
+ return messagesToMove;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addAdditionalEntryPoints(Collection<ISequenceEvent> sequenceElements) {
+ if (sequenceElements != null && !sequenceElements.isEmpty()) {
+ this.otherEntryPoints.addAll(sequenceElements);
+ }
+ }
+
+ /**
+ * Overridden to do validation.
+ *
+ * {@inheritDoc}
+ */
+ protected void doValidation() {
+ populateMoves();
+ populateMessageToResize();
+ categorizeMoves();
+
+ checkMoves();
+
+ // Avoid expansion with non complete moves
+ if (!startReflexiveMessageToResize.isEmpty() || !endReflexiveMessageToResize.isEmpty()) {
+ valid = valid && (expansionZone == null || expansionZone.isEmpty());
+ }
+ }
+
+ private void populateMoves() {
+ Set<ISequenceEvent> movedEvents = new ISequenceEventQuery(primarySelected).getAllSequenceEventToMoveWith(otherEntryPoints);
+ if (movedEvents != null && !movedEvents.isEmpty()) {
+ movedElements.addAll(movedEvents);
+ }
+ }
+
+ private void populateMessageToResize() {
+ for (Execution movedExec : Iterables.filter(movedElements, Execution.class)) {
+
+ Option<Message> startMessage = movedExec.getStartMessage();
+ if (startMessage.some() && startMessage.get().surroundsEventOnSameLifeline()) {
+ startReflexiveMessageToResize.add(startMessage.get());
+ }
+
+ Option<Message> endMessage = movedExec.getEndMessage();
+ if (endMessage.some() && endMessage.get().surroundsEventOnSameLifeline()) {
+ endReflexiveMessageToResize.add(endMessage.get());
+ }
+ }
+ }
+
+ private void categorizeMoves() {
+ MoveSwitch moveAnalyzer = new MoveSwitch();
+ for (ISequenceEvent movedEvent : Lists.newArrayList(movedElements)) {
+ Range extendedRange = moveAnalyzer.doSwitch(movedEvent);
+ globalMovedRange = globalMovedRange.union(extendedRange);
+ }
+
+ Set<ISequenceEvent> move = Sets.newHashSet();
+ move.add(primarySelected);
+ move.addAll(otherEntryPoints);
+ Iterables.retainAll(move, sequenceNodesToMove);
+ Iterables.addAll(topLevelElements, move);
+
+ Rectangle movedRange = new Rectangle(0, globalMovedRange.getLowerBound(), 0, globalMovedRange.width());
+ globalMovedRange = Range.verticalRange(request.getLogicalTransformedRectangle(movedRange));
+ }
+
+ private void checkMoves() {
+ for (ISequenceEvent ise : topLevelElements) {
+ if (!moveIsValid(ise, true)) {
+ valid = false;
+ eventInError.add(ise);
+ // break;
+ }
+ }
+
+ if (valid) {
+ Iterable<ISequenceEvent> otherMovedElements = Iterables.filter(movedElements, Predicates.not(Predicates.in(topLevelElements)));
+ for (ISequenceEvent ise : otherMovedElements) {
+ if (!(ise instanceof Operand) && !moveIsValid(ise, false)) {
+ valid = false;
+ eventInError.add(ise);
+ }
+ }
+ }
+
+ for (Message resizedMsg : Iterables.concat(startReflexiveMessageToResize, endReflexiveMessageToResize)) {
+ boolean currentResizeIsValid = rangeFunction.apply(resizedMsg).width() >= LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ valid = valid && currentResizeIsValid;
+ if (!currentResizeIsValid) {
+ eventInError.add(resizedMsg);
+ }
+ }
+
+ valid = valid && checkConflictesInFinalPositions() && checkTitleZonesInFinalPositions();
+ }
+
+ private boolean checkConflictesInFinalPositions() {
+ List<Integer> conflicts = Lists.newArrayList();
+ conflicts.addAll(new PositionsChecker(getDiagram(), rangeFunction).getInvalidPositions());
+
+ if (!conflicts.isEmpty()) {
+ // try with global moved range...
+ if (!expansionZone.isEmpty() && globalMovedRange != expansionZone) {
+ expansionZone = globalMovedRange;
+ conflicts = Lists.newArrayList();
+ conflicts.addAll(new PositionsChecker(getDiagram(), rangeFunction).getInvalidPositions());
+ }
+ }
+
+ invalidPositions.addAll(conflicts);
+ return conflicts.isEmpty();
+ }
+
+ private boolean checkTitleZonesInFinalPositions() {
+ SequenceDiagram diagram = getDiagram();
+ Collection<Range> conflicts = Lists.newArrayList();
+ Collection<Range> titleZones = getTitleZoneRanges(diagram);
+
+ for (ISequenceEvent movedElement : movedElements) {
+ Range movedRange = rangeFunction.apply(movedElement);
+ if (movedElement instanceof State && movedElement.isLogicallyInstantaneous()) {
+ movedRange = new Range(movedRange.middleValue(), movedRange.middleValue());
+ }
+ for (Range title : titleZones) {
+ if (title.includes(movedRange.getLowerBound()) || title.includes(movedRange.getUpperBound())) {
+ conflicts.add(title);
+ }
+ }
+ }
+
+ invalidRanges.addAll(conflicts);
+ return conflicts.isEmpty();
+ }
+
+ private Collection<Range> getTitleZoneRanges(SequenceDiagram diagram) {
+ Collection<Range> titleZones = Lists.newArrayList();
+ for (CombinedFragment unmovedCF : Iterables.filter(diagram.getAllCombinedFragments(), Predicates.not(Predicates.in(movedElements)))) {
+ int titleZoneLowerBound = rangeFunction.apply(unmovedCF).getLowerBound();
+ int titleZoneUpperBound = rangeFunction.apply(unmovedCF.getFirstOperand()).getLowerBound();
+
+ titleZones.add(new Range(titleZoneLowerBound, titleZoneUpperBound));
+ }
+ return titleZones;
+ }
+
+ private boolean moveIsValid(ISequenceEvent ise, boolean topLevel) {
+ final Range futureExtRange = getFutureExtendedRange(ise);
+ Option<Lifeline> lifeline = ise.getLifeline();
+ boolean result = true;
+
+ if (lifeline.some()) {
+ EventFinder futureParentFinder = new EventFinder(lifeline.get());
+ futureParentFinder.setEventsToIgnore(Predicates.equalTo(ise));
+ futureParentFinder.setVerticalRangefunction(rangeFunction);
+ Range insertionPoint = getInsertionPoint(ise, futureExtRange);
+ ISequenceEvent insertionParent = futureParentFinder.findMostSpecificEvent(insertionPoint);
+
+ if (insertionParent == null) {
+ if (lifeline.get().isExplicitlyCreated() || lifeline.get().isExplicitlyDestroyed()) {
+ return false;
+ } else {
+ insertionParent = lifeline.get();
+ }
+ }
+
+ // check Operand;
+ boolean stableOperand = checkOperandStability(ise, topLevel, insertionParent);
+
+ // check expansion need
+ boolean validExpansion = stableOperand && checkExpansionNeed(ise, topLevel, insertionParent, futureExtRange, insertionPoint, Collections.singletonList(lifeline.get()));
+
+ // Test remote expansion
+ boolean validRemoteExpansion = validExpansion && checkRemoteExpansion(ise, topLevel, futureExtRange, insertionPoint);
+
+ result = stableOperand && validExpansion && validRemoteExpansion;
+ } else if (ise instanceof InteractionUse) {
+ InteractionUseMoveValidator subValidator = new InteractionUseMoveValidator((InteractionUse) ise, request);
+ subValidator.setMovedElements(movedElements);
+ result = subValidator.isValid();
+ expansionZone = expansionZone.union(subValidator.getExpansionZone());
+ } else if (ise instanceof CombinedFragment) {
+ CombinedFragmentMoveValidator subValidator = new CombinedFragmentMoveValidator((CombinedFragment) ise, request);
+ subValidator.setMovedElements(movedElements);
+ result = subValidator.isValid();
+ expansionZone = expansionZone.union(subValidator.getExpansionZone());
+ } else if (ise instanceof Message) {
+ result = messageMoveIsValid((Message) ise);
+ }
+ return result;
+ }
+
+ private Range getInsertionPoint(ISequenceEvent ise, Range futureExtRange) {
+ int insertionY = futureExtRange.getLowerBound();
+
+ if (ise instanceof State && ise.isLogicallyInstantaneous()) {
+ insertionY = futureExtRange.middleValue();
+ }
+
+ return new Range(insertionY, insertionY);
+ }
+
+ private boolean messageMoveIsValid(final Message message) {
+ boolean result = true;
+ Option<Operand> parentOperand = message.getParentOperand();
+
+ // If parent operand is moved too, no check for source/target validity :
+ // it will not change.
+ if (!(parentOperand.some() && movedElements.contains(parentOperand.get()))) {
+
+ ISequenceEvent potentialSource = getMessageEnd(message, message.getSourceLifeline(), parentOperand);
+ ISequenceEvent potentialTarget = getMessageEnd(message, message.getTargetLifeline(), parentOperand);
+
+ // Validate that the source and target will not overlap a frame
+
+ if (potentialSource instanceof AbstractFrame || potentialSource instanceof State || potentialTarget instanceof AbstractFrame || potentialTarget instanceof State) {
+ result = false;
+ } else if (potentialSource != null && potentialTarget != null) {
+ // We filter found or lost message because for them move is
+ // always allowed
+
+ Range finalRange = rangeFunction.apply(message);
+ int lBound = finalRange.getLowerBound();
+ int uBound = finalRange.getUpperBound();
+
+ Operand srcOperand = null;
+ if (potentialSource instanceof Operand) {
+ srcOperand = (Operand) potentialSource;
+ } else if (potentialSource instanceof Execution) {
+ srcOperand = new ParentOperandFinder(potentialSource, rangeFunction).getParentOperand(new Range(lBound, lBound)).get();
+ }
+
+ Operand tgtOperand = null;
+ if (potentialTarget instanceof Operand) {
+ tgtOperand = (Operand) potentialTarget;
+ } else if (potentialTarget instanceof Execution) {
+ tgtOperand = new ParentOperandFinder(potentialTarget, rangeFunction).getParentOperand(new Range(uBound, uBound)).get();
+ }
+ result = srcOperand == tgtOperand;
+ }
+ }
+ return result;
+ }
+
+ private ISequenceEvent getMessageEnd(final Message message, Option<Lifeline> lifeline, Option<Operand> parentOperand) {
+ if (lifeline.some()) {
+ EventFinder newEndFinder = new EventFinder(lifeline.get());
+ newEndFinder.setReconnection(false);
+
+ Range lookedRange = rangeFunction.apply(message);
+ newEndFinder.setVerticalRangefunction(rangeFunction);
+
+ return newEndFinder.findMostSpecificEvent(lookedRange);
+ }
+ return null;
+ }
+
+ private boolean checkOperandStability(ISequenceEvent ise, boolean topLevel, ISequenceEvent insertionParent) {
+ Option<Operand> parentOperand = ise.getParentOperand();
+ Operand futureOperand = null;
+ if (insertionParent instanceof Operand) {
+ futureOperand = (Operand) insertionParent;
+ } else {
+ futureOperand = insertionParent.getParentOperand().get();
+ }
+
+ return true; // futureOperand == parentOperand.get();
+ }
+
+ private boolean checkExpansionNeed(ISequenceEvent ise, boolean topLevel, ISequenceEvent insertionParent, Range futureExtRange, Range insertionPoint, Collection<Lifeline> lifelines) {
+ List<ISequenceEvent> toIgnore = Lists.newArrayList(movedElements);
+ toIgnore.addAll(startReflexiveMessageToResize);
+ toIgnore.addAll(endReflexiveMessageToResize);
+
+ boolean canChildOccupy = movedElements.contains(insertionParent) || insertionParent.canChildOccupy(ise, futureExtRange, toIgnore, lifelines);
+ if (!canChildOccupy) {
+ if (topLevel && !expansionZone.isEmpty()) {
+ expansionZone = globalMovedRange;
+ canChildOccupy = true;
+ } else if (topLevel || expansionZone.isEmpty()) {
+ if (insertionParent.canChildOccupy(ise, insertionPoint, toIgnore, lifelines)) {
+ if (!(ise instanceof State && ise.isLogicallyInstantaneous())) {
+ expansionZone = expansionZone.union(futureExtRange);
+ }
+ canChildOccupy = true;
+ }
+ } else if (expansionZone.includes(futureExtRange)) {
+ canChildOccupy = true;
+ }
+ }
+ return canChildOccupy;
+ }
+
+ private boolean checkRemoteExpansion(ISequenceEvent ise, boolean topLevel, Range futureExtRange, Range insertionPoint) {
+ if (ise instanceof Execution) {
+ Execution exec = (Execution) ise;
+ Option<Message> startMessage = exec.getStartMessage();
+ Option<Message> endMessage = exec.getEndMessage();
+
+ if (startMessage.some() && endMessage.some() && !startReflexiveMessageToResize.contains(startMessage.get()) && !endReflexiveMessageToResize.contains(endMessage.get())) {
+ Option<Lifeline> startLifeline = startMessage.get().getSourceLifeline();
+ // Should be the same...
+ Option<Lifeline> targetLifeline = endMessage.get().getTargetLifeline();
+
+ Range srcInsertionRange = rangeFunction.apply(startMessage.get());
+ ISequenceEvent remoteSource = getRemoteEnd(startMessage, startLifeline, srcInsertionRange);
+
+ // Expansion ?
+ Range tgtInsertionRange = rangeFunction.apply(endMessage.get());
+ ISequenceEvent remoteTarget = getRemoteEnd(endMessage, targetLifeline, tgtInsertionRange);
+
+ boolean remoteCanChildOccupy = startLifeline.some() && remoteSource != null && remoteTarget == remoteSource || !startLifeline.some();
+ boolean tryExpand = topLevel || expansionZone.isEmpty();
+ boolean canExpandedChildOccupy = remoteSource != null && remoteSource.canChildOccupy(ise, srcInsertionRange);
+ if (!remoteCanChildOccupy && tryExpand && canExpandedChildOccupy) {
+ expansionZone = expansionZone.union(futureExtRange);
+ remoteCanChildOccupy = true;
+ }
+ return remoteCanChildOccupy;
+ }
+ }
+ return true;
+ }
+
+ private ISequenceEvent getRemoteEnd(Option<Message> message, Option<Lifeline> lifeline, Range insertionRange) {
+ ISequenceEvent remoteEnd = null;
+ if (lifeline.some()) {
+ EventFinder remoteSrcFinder = new EventFinder(lifeline.get());
+ remoteSrcFinder.setEventsToIgnore(Predicates.equalTo((ISequenceEvent) message.get()));
+ remoteSrcFinder.setVerticalRangefunction(rangeFunction);
+ remoteSrcFinder.setExpansionZone(expansionZone);
+ remoteSrcFinder.setReconnection(true);
+
+ remoteEnd = remoteSrcFinder.findMostSpecificEvent(insertionRange);
+ }
+ return remoteEnd;
+ }
+
+ private Range getFutureExtendedRange(ISequenceEvent ise) {
+ Range futureExtRange = rangeFunction.apply(ise);
+ if (ise instanceof Execution) {
+ Execution exec = (Execution) ise;
+ Option<Message> startMessage = exec.getStartMessage();
+ if (startMessage.some() && !startReflexiveMessageToResize.contains(startMessage.get())) {
+ futureExtRange = futureExtRange.union(rangeFunction.apply(startMessage.get()));
+ }
+ Option<Message> endMessage = exec.getEndMessage();
+ if (endMessage.some() && !endReflexiveMessageToResize.contains(endMessage.get())) {
+ futureExtRange = futureExtRange.union(rangeFunction.apply(endMessage.get()));
+ }
+ }
+ return futureExtRange;
+ }
+
+ /**
+ * Specific switch returning allowing to categorize and event.
+ *
+ * The doSwitch will return the extended range occupied by the event
+ * (including the linked messages for reflexives executions).
+ *
+ * @author mporhel
+ *
+ */
+ public class MoveSwitch extends ISequenceElementSwitch<Range> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range caseMessage(Message movedEvent) {
+ Predicate<Message> toMove = new Predicate<Message>() {
+ public boolean apply(Message input) {
+ boolean movedBySrc = movedElements.contains(input.getSourceElement());
+ boolean movedByTgt = movedElements.contains(input.getTargetElement());
+
+ return !(movedBySrc && movedByTgt);
+ }
+ };
+ if (toMove.apply(movedEvent)) {
+ if (startReflexiveMessageToResize.contains(movedEvent) || endReflexiveMessageToResize.contains(movedEvent)) {
+ movedElements.remove(movedEvent);
+ return Range.emptyRange();
+ }
+ messagesToMove.add(movedEvent);
+ } else {
+ startReflexiveMessageToResize.remove(movedEvent);
+ endReflexiveMessageToResize.remove(movedEvent);
+ }
+ return movedEvent.getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range caseExecution(Execution movedEvent) {
+ ISequenceEvent hierarchicalParentEvent = movedEvent.getHierarchicalParentEvent();
+ if (hierarchicalParentEvent instanceof ISequenceNode && !movedElements.contains(hierarchicalParentEvent)) {
+ sequenceNodesToMove.add(movedEvent);
+ }
+
+ Range extendedVerticalRange = movedEvent.getExtendedVerticalRange();
+ Option<Message> startMessage = movedEvent.getStartMessage();
+ if (startMessage.some() && startReflexiveMessageToResize.contains(startMessage.get())) {
+ extendedVerticalRange = new Range(startMessage.get().getVerticalRange().getUpperBound(), extendedVerticalRange.getUpperBound());
+ }
+
+ Option<Message> endMessage = movedEvent.getEndMessage();
+ if (endMessage.some() && endReflexiveMessageToResize.contains(endMessage.get())) {
+ extendedVerticalRange = new Range(extendedVerticalRange.getLowerBound(), endMessage.get().getVerticalRange().getLowerBound());
+ }
+
+ return extendedVerticalRange;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range caseState(State movedEvent) {
+ ISequenceEvent hierarchicalParentEvent = movedEvent.getHierarchicalParentEvent();
+ if (hierarchicalParentEvent instanceof ISequenceNode && !movedElements.contains(hierarchicalParentEvent)) {
+ sequenceNodesToMove.add(movedEvent);
+ }
+ return movedEvent.getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range caseFrame(AbstractFrame movedEvent) {
+ sequenceNodesToMove.add(movedEvent);
+ return movedEvent.getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range caseOperand(Operand movedEvent) {
+ // Do nothing, operand is silently moved by its parent combined
+ // fragment.
+ return movedEvent.getVerticalRange();
+ }
+ }
+
+ /**
+ * Get the validator from the request extended data or a new one.
+ *
+ * @param cbr
+ * the current request
+ * @param requestQuery
+ * a query on the current request.
+ * @param host
+ * the host
+ * @return a validator.
+ */
+ @SuppressWarnings("unchecked")
+ public static ISEComplexMoveValidator getOrCreateValidator(ChangeBoundsRequest cbr, RequestQuery requestQuery, ISequenceEvent host) {
+ ISEComplexMoveValidator validator = null;
+ Object object = cbr.getExtendedData().get(VALIDATOR);
+ if (object instanceof ISEComplexMoveValidator) {
+ validator = (ISEComplexMoveValidator) object;
+ if (validator.request == null || !validator.request.getLogicalDelta().equals(requestQuery.getLogicalDelta())) {
+ validator = null;
+ }
+ }
+
+ if (validator == null && requestQuery.isMove()) {
+ Collection<ISequenceEvent> selectedIses = new RequestQuery(cbr).getISequenceEvents();
+ validator = new ISEComplexMoveValidator(host, requestQuery);
+ validator.addAdditionalEntryPoints(selectedIses);
+ cbr.getExtendedData().put(VALIDATOR, validator);
+ }
+ return validator;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleGraphicalHorizontalOrderingComparator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleGraphicalHorizontalOrderingComparator.java
new file mode 100644
index 0000000000..62be688a3b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleGraphicalHorizontalOrderingComparator.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Comparator;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+
+/**
+ * Comparator to have calculated ordering in x coordinate.
+ *
+ * @author edugueperoux
+ */
+public class InstanceRoleGraphicalHorizontalOrderingComparator implements Comparator<InstanceRole> {
+
+ private Map<InstanceRole, Point> moveDeltas;
+
+ /**
+ * Default constructor.
+ */
+ public InstanceRoleGraphicalHorizontalOrderingComparator() {
+ }
+
+ public Map<InstanceRole, Point> getMoveDeltas() {
+ return moveDeltas;
+ }
+
+ public void setMoveDeltas(Map<InstanceRole, Point> moveDeltas) {
+ this.moveDeltas = moveDeltas;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compare(InstanceRole o1, InstanceRole o2) {
+ Node o1Node = o1.getNotationNode();
+ Bounds o1NodeBounds = (Bounds) o1Node.getLayoutConstraint();
+ int x1 = o1NodeBounds.getX();
+ if (getMoveDeltas() != null && getMoveDeltas().containsKey(o1)) {
+ x1 += getMoveDeltas().get(o1).x;
+ }
+ Node o2Node = o2.getNotationNode();
+ Bounds o2NodeBounds = (Bounds) o2Node.getLayoutConstraint();
+ int x2 = o2NodeBounds.getX();
+ if (getMoveDeltas() != null && getMoveDeltas().containsKey(o2)) {
+ x2 += getMoveDeltas().get(o2).x;
+ }
+ return x1 - x2;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleMoveValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleMoveValidator.java
new file mode 100644
index 0000000000..9f80978d49
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleMoveValidator.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.diagram.business.internal.query.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+
+/**
+ * Validator for ChangeBoundsRequest of type RequestConstants#REQ_MOVE.
+ *
+ * @author edugueperoux
+ */
+public class InstanceRoleMoveValidator extends AbstractInstanceRoleValidator {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isValid(ChangeBoundsRequest request) {
+ boolean valid = super.isValid(request);
+
+ if (instanceRoles.size() != 0) {
+ SequenceDiagram sequenceDiagram = instanceRoles.get(0).getDiagram();
+ List<InstanceRole> allInstanceRoles = sequenceDiagram.getSortedInstanceRole();
+
+ RequestQuery query = new RequestQuery(request);
+ Point moveDelta = query.getLogicalDelta().getLocation();
+
+ Collections.sort(instanceRoles, comparator);
+
+ // if move request is constrained then it's a explicit user move
+ // request
+ // otherwise it's a indirect request from ConnectionCreationTool for
+ // a
+ // Create Message for example
+ if (!request.isConstrainedMove()) {
+ moveDelta.y = 0;
+ }
+
+ Iterable<Rectangle> notMovedIRBounds = Iterables.transform(Iterables.filter(allInstanceRoles, Predicates.not(Predicates.in(instanceRoles))), ISequenceElement.PROPER_LOGICAL_BOUNDS);
+
+ // Iterate on all instanceRoles to move from the request
+ for (InstanceRole instanceRole : instanceRoles) {
+ moveDeltas.put(instanceRole, moveDelta.getCopy());
+
+ Rectangle boundBeforeResizing = instanceRole.getBounds();
+ Rectangle boundAfterResizing = boundBeforeResizing.getTranslated(moveDelta);
+
+ for (Rectangle notMovedBounds : notMovedIRBounds) {
+ int nmbLeftX = notMovedBounds.getLeft().x;
+ int nmbRightX = notMovedBounds.getRight().x;
+ int mLeftX = boundAfterResizing.getLeft().x;
+ boolean leftOverlapFixIR = nmbLeftX <= mLeftX && mLeftX <= nmbRightX;
+
+ if (leftOverlapFixIR) {
+ valid = false;
+ break;
+ }
+ }
+ }
+ }
+ return valid;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleResizeValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleResizeValidator.java
new file mode 100644
index 0000000000..cf83eab9f1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InstanceRoleResizeValidator.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.business.internal.query.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+
+/**
+ * Validator for ChangeBoundsRequest of type RequestConstants#REQ_RESIZE.
+ *
+ * @author edugueperoux
+ *
+ */
+public class InstanceRoleResizeValidator extends AbstractInstanceRoleValidator {
+
+ private Map<InstanceRole, Dimension> sizeDeltas = new HashMap<InstanceRole, Dimension>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isValid(ChangeBoundsRequest request) {
+ boolean valid = super.isValid(request);
+
+ if (instanceRoles.size() != 0) {
+ SequenceDiagram sequenceDiagram = instanceRoles.get(0).getDiagram();
+ List<InstanceRole> preResizeOrder = sequenceDiagram.getSortedInstanceRole();
+
+ RequestQuery query = new RequestQuery(request);
+ Rectangle logicalDelta = query.getLogicalDelta();
+
+ Point moveDelta = logicalDelta.getLocation();
+ moveDelta.y = 0;
+ Dimension sizeDelta = logicalDelta.getSize();
+
+ for (InstanceRole instanceRole : instanceRoles) {
+ moveDeltas.put(instanceRole, moveDelta.getCopy());
+ sizeDeltas.put(instanceRole, sizeDelta.getCopy());
+
+ Rectangle boundBeforeResizing = instanceRole.getBounds();
+ Rectangle boundAfterResizing = boundBeforeResizing.getTranslated(moveDelta).resize(sizeDelta);
+
+ if (boundAfterResizing.width <= 0) {
+ valid = false;
+ }
+ }
+
+ // Avoid all reorders
+ List<InstanceRole> postResizeOrder = getPostResizeOrder(preResizeOrder);
+ if (!Iterables.elementsEqual(preResizeOrder, postResizeOrder)) {
+ valid = false;
+ }
+ }
+ return valid;
+ }
+
+ private List<InstanceRole> getPostResizeOrder(List<InstanceRole> allInstanceRoles) {
+ List<InstanceRole> result = Lists.newArrayList(allInstanceRoles);
+ comparator.setMoveDeltas(moveDeltas);
+ Collections.sort(result, comparator);
+ comparator.setMoveDeltas(null);
+ return result;
+ }
+
+ public Map<InstanceRole, Dimension> getSizeDeltas() {
+ return sizeDeltas;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseMoveValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseMoveValidator.java
new file mode 100644
index 0000000000..2194c3af2e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseMoveValidator.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * This class is responsible to check whether a resize request on an interaction
+ * use should be accepted (i.e. it would produce a well-formed diagram). While
+ * doing the validation, it also stores all the relevant information required to
+ * actually perform the resize properly.
+ *
+ * @author mporhel
+ */
+public class InteractionUseMoveValidator extends AbstractInteractionFrameValidator {
+
+ /**
+ * Constructor.
+ *
+ * @param interactionUse
+ * the interactionUse which will be moved.
+ * @param requestQuery
+ * a query on the move request targeting the execution.
+ */
+ public InteractionUseMoveValidator(InteractionUse interactionUse, RequestQuery requestQuery) {
+ super(interactionUse, requestQuery);
+ Preconditions.checkArgument(requestQuery.isMove());
+ defaultFrameHeight = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceEvent> getFinalParents() {
+ // Possibility to handle "reparent" and insertion"
+ Collection<ISequenceEvent> finalParents = Sets.newLinkedHashSet();
+ Range insertionPoint = new Range(finalRange.getLowerBound(), finalRange.getLowerBound());
+ Collection<Lifeline> coveredLifelines = frame.computeCoveredLifelines();
+ for (Lifeline lifeline : coveredLifelines) {
+ EventFinder finder = new EventFinder(lifeline);
+ finder.setEventsToIgnore(Predicates.in(Collections.<ISequenceEvent> singletonList(frame)));
+ ISequenceEvent localParent = finder.findMostSpecificEvent(insertionPoint);
+ if (localParent != null) {
+ finalParents.add(localParent);
+ }
+ }
+ return finalParents;
+ // return frame.computeParentEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * expand to handle insertion.
+ */
+ @Override
+ protected boolean canExpand() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Range computeExpansionZone() {
+ Range expansionZone = Range.emptyRange();
+ RequestQuery requestQuery = getRequestQuery();
+ if (requestQuery.isMove()) { // requestQuery.getLogicalDelta().y > 0) {
+ expansionZone = finalRange;
+ }
+ return expansionZone;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseResizeValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseResizeValidator.java
new file mode 100644
index 0000000000..35c3da6fb8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/InteractionUseResizeValidator.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * This class is responsible to check whether a resize request on an interaction
+ * use should be accepted (i.e. it would produce a well-formed diagram). While
+ * doing the validation, it also stores all the relevant information required to
+ * actually perform the resize properly.
+ *
+ * @author mporhel
+ */
+public class InteractionUseResizeValidator extends AbstractInteractionFrameValidator {
+ /**
+ * Constructor.
+ *
+ * @param interactionUse
+ * the interactionUse which will be resized.
+ * @param requestQuery
+ * a query on the resize request targeting the execution.
+ */
+ protected InteractionUseResizeValidator(InteractionUse interactionUse, RequestQuery requestQuery) {
+ super(interactionUse, requestQuery);
+ defaultFrameHeight = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void validate() {
+ if (!(getRequestQuery().isResizeFromTop() || getRequestQuery().isResizeFromBottom())) {
+ valid = false;
+ } else {
+ super.validate();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceEvent> getFinalParents() {
+ return frame.computeParentEvents();
+ }
+
+ /**
+ * Resize do not authorize auto expand.
+ *
+ * @return true;
+ */
+ @Override
+ protected boolean canExpand() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Range computeExpansionZone() {
+ Range expansionZone = Range.emptyRange();
+ if (getRequestQuery().isResizeFromBottom() && getRequestQuery().getLogicalDelta().height > 0) {
+ expansionZone = new Range(initialRange.getUpperBound(), finalRange.getUpperBound());
+ }
+ return expansionZone;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/OperandResizeValidator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/OperandResizeValidator.java
new file mode 100644
index 0000000000..4a1a5e9a0b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/OperandResizeValidator.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.util.RequestQuery;
+
+/**
+ * This class is responsible to check whether a resize request on an operand
+ * should be accepted (i.e. it would produce a well-formed diagram). While doing
+ * the validation, it also stores all the relevant information required to
+ * actually perform the resize properly.
+ *
+ * @author smonnier
+ */
+public class OperandResizeValidator extends AbstractOperandValidator {
+
+ /**
+ * Constructor.
+ *
+ * @param operand
+ * the operand which will be resized.
+ * @param requestQuery
+ * a query on the resize request targeting the execution.
+ */
+ public OperandResizeValidator(Operand operand, RequestQuery requestQuery) {
+ super(operand, requestQuery);
+ Preconditions.checkArgument(requestQuery.isResizeFromTop() || requestQuery.isResizeFromBottom());
+ }
+
+ // /**
+ // * {@inheritDoc}
+ // */
+ // @Override
+ // protected Collection<? extends ISequenceEvent> getFinalParents() {
+ // return operand.computeParentEvents();
+ // }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/PositionsChecker.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/PositionsChecker.java
new file mode 100644
index 0000000000..2db331bcb3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/validator/PositionsChecker.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.validator;
+
+import java.util.Collection;
+import java.util.Set;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Helper to check position of events on the diagram.
+ *
+ * @author mporhel
+ *
+ */
+public class PositionsChecker {
+
+ private SequenceDiagram diagram;
+
+ private Function<ISequenceEvent, Range> rangeFunction = ISequenceEvent.VERTICAL_RANGE;
+
+ /**
+ * Constructor. Position will be computed using the events vertical range.
+ *
+ * @param diagram
+ * the diagram to check.
+ */
+ public PositionsChecker(SequenceDiagram diagram) {
+ this.diagram = diagram;
+ }
+
+ /**
+ * Constructor. Position will be computed using the provided function.
+ *
+ * @param diagram
+ * the diagram to check.
+ * @param rangeFunction
+ * function to compute range (future range for example).
+ *
+ */
+ public PositionsChecker(SequenceDiagram diagram, Function<ISequenceEvent, Range> rangeFunction) {
+ this.diagram = diagram;
+
+ if (rangeFunction != null) {
+ this.rangeFunction = rangeFunction;
+ }
+ }
+
+ /**
+ * Inspect all sequence events and check that there is no conflicts.
+ *
+ * @return a collection of invalid positions.
+ */
+ public Collection<Integer> getInvalidPositions() {
+ final Multiset<Integer> positions = HashMultiset.create();
+ // Check conflicts
+ for (ISequenceEvent ise : diagram.getAllOrderedDelimitedSequenceEvents()) {
+ Range futureRange = rangeFunction.apply(ise);
+ int futureLowerBound = futureRange.getLowerBound();
+ int futureUpperBound = futureRange.getUpperBound();
+
+ if (ise instanceof Execution) {
+ Execution exec = (Execution) ise;
+ if (!exec.getStartMessage().some()) {
+ positions.add(futureLowerBound);
+ }
+ if (!exec.getEndMessage().some()) {
+ positions.add(futureUpperBound);
+ }
+ } else if (ise instanceof Operand) {
+ positions.add(futureLowerBound);
+ } else if (ise instanceof Message) {
+ positions.add(futureLowerBound);
+ if (((Message) ise).isReflective()) {
+ positions.add(futureUpperBound);
+ }
+ } else if (ise instanceof State && ise.isLogicallyInstantaneous()) {
+ positions.add(futureRange.middleValue());
+ } else {
+ positions.add(futureLowerBound);
+ positions.add(futureUpperBound);
+ }
+ }
+
+ Set<Integer> invalidPositions = Sets.newHashSet();
+ Iterables.addAll(invalidPositions, Iterables.filter(positions, new Predicate<Integer>() {
+ public boolean apply(Integer input) {
+ int count = positions.count(input);
+ return count != 1;
+ }
+ }));
+
+ return invalidPositions;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/CombinedFragmentInvisibleResizableCompartmentFigure.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/CombinedFragmentInvisibleResizableCompartmentFigure.java
new file mode 100644
index 0000000000..4d977463b9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/CombinedFragmentInvisibleResizableCompartmentFigure.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.MarginBorder;
+import org.eclipse.draw2d.ScrollPane;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode;
+
+import org.eclipse.sirius.diagram.ui.tools.api.figure.InvisibleResizableCompartmentFigure;
+
+public class CombinedFragmentInvisibleResizableCompartmentFigure extends InvisibleResizableCompartmentFigure {
+ /**
+ * Create a new compartment figure without borders. Overridden to remove
+ * border margin.
+ *
+ * @param title
+ * compartment title.
+ * @param mode
+ * mapping mode.
+ */
+ public CombinedFragmentInvisibleResizableCompartmentFigure(String title, IMapMode mode) {
+ super(title, mode);
+ }
+
+ /**
+ * {@inheritDoc} Overridden to remove border margin.
+ */
+ @Override
+ protected void configureFigure(IMapMode mm) {
+ super.configureFigure(mm);
+ ScrollPane scrollpane = getScrollPane();
+
+ int mb = mm.DPtoLP(0);
+ scrollpane.setBorder(new MarginBorder(mb, mb, mb, mb));
+ int sz = mm.DPtoLP(0);
+ scrollpane.setMinimumSize(new Dimension(sz, sz));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/ExecutionItemLocator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/ExecutionItemLocator.java
new file mode 100644
index 0000000000..7d646c14d9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/ExecutionItemLocator.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.IFigure;
+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.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.description.StateMapping;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.LayoutEditPartConstants;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator;
+
+/**
+ * Specific DBorderItemLocator to handle border item offset and side
+ * computation.
+ *
+ * @author mporhel
+ *
+ */
+public class ExecutionItemLocator extends DBorderItemLocator {
+ private final IGraphicalEditPart owner;
+
+ /**
+ * Create an {@link ExecutionItemLocator} with the specified parentFigure.
+ *
+ * @param owner
+ * the owner edit part.
+ * @param parentFigure
+ * the parent figure.
+ */
+ public ExecutionItemLocator(IGraphicalEditPart owner, IFigure parentFigure) {
+ super(parentFigure);
+ this.owner = owner;
+ setCurrentSideOfParent(LayoutEditPartConstants.EXECUTION_SIDE);
+ setPreferredSideOfParent(LayoutEditPartConstants.EXECUTION_SIDE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void relocate(IFigure borderItem) {
+ super.relocate(borderItem);
+ if (isFigureForStateElement(borderItem)) {
+ centerFigureOnParent(borderItem);
+ }
+
+ // Force size
+ borderItem.setSize(getCollapsedSize(borderItem));
+
+ unfix();
+ }
+
+ private void centerFigureOnParent(IFigure borderItem) {
+ Rectangle parentBounds = getParentFigure().getBounds();
+ int parentCenter = parentBounds.getCenter().x;
+ Rectangle myBounds = borderItem.getBounds().getCopy();
+ int x = parentCenter - (myBounds.width / 2);
+ borderItem.setLocation(new Point(x, myBounds.getLocation().y));
+ }
+
+ private boolean isFigureForStateElement(IFigure borderItem) {
+ for (IGraphicalEditPart childPart : Iterables.filter(owner.getChildren(), IGraphicalEditPart.class)) {
+ if (childPart.getFigure() == borderItem) {
+ return isStateElement(childPart);
+ }
+ }
+ return false;
+ }
+
+ private boolean isStateElement(IGraphicalEditPart childPart) {
+ EObject obj = childPart.resolveSemanticElement();
+ if (obj instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) obj;
+ return dde.getMapping() instanceof StateMapping;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBorderItemOffset(Dimension borderItemOffset) {
+ super.setBorderItemOffset(getExecutionOffset());
+ }
+
+ private Dimension getExecutionOffset() {
+ Dimension offset = new Dimension(LayoutEditPartConstants.EXECUTION_BORDER_ITEM_OFFSET);
+ Rectangle currentBounds = getConstraint();
+ IFigure parentFigure = getParentFigure();
+ if (parentFigure instanceof LifelineNodeFigure) {
+ // we need to have the center of the execution aligned with the
+ // center of the lifeline
+ Rectangle parentBounds = parentFigure.getBounds();
+ offset.width = parentBounds.width / 2 + currentBounds.width / 2;
+ } else if (currentBounds.width == 0) {
+ offset.width = 0;
+ }
+ return offset;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCurrentSideOfParent(int side) {
+ super.setCurrentSideOfParent(LayoutEditPartConstants.EXECUTION_SIDE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPreferredSideOfParent(int side) {
+ super.setPreferredSideOfParent(LayoutEditPartConstants.EXECUTION_SIDE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Point locateOnParent(Point suggestedLocation, int suggestedSide, IFigure borderItem) {
+ Point locateOnParent = super.locateOnParent(suggestedLocation, suggestedSide, borderItem);
+ return new Point(locateOnParent.x, suggestedLocation.y);
+ }
+
+ /**
+ * Gets the size of the border item figure.
+ *
+ * @param borderItem
+ * {@link IFigure} representing a Execution
+ * @return the size of the border item figure.
+ */
+ protected final Dimension getCollapsedSize(IFigure borderItem) {
+ Dimension size = getConstraint().getSize().getCopy();
+
+ // Width can be empty for collapsing, do not use size.isEmpty()
+ if (size.height == 0) {
+ Dimension preferredSize = borderItem.getPreferredSize();
+ size.height = preferredSize != null ? preferredSize.height : 0;
+ }
+
+ return size;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/HorizontalGuide.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/HorizontalGuide.java
new file mode 100644
index 0000000000..250f54a692
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/HorizontalGuide.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Color;
+
+/**
+ * A horizontal line across the whole diagram, useful as feedback for sequence
+ * diagrams where the vertical location of elements relative to each others is
+ * significant.
+ *
+ * @author pcdavid
+ */
+public class HorizontalGuide extends Figure {
+ private final int y;
+
+ /**
+ * Creates a new horizontal guide.
+ *
+ * @param color
+ * the color of the line.
+ * @param y
+ * the vertical location of the guide.
+ */
+ public HorizontalGuide(Color color, int y) {
+ this.y = y;
+ setForegroundColor(color);
+ super.setOpaque(true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void paintFigure(Graphics graphics) {
+ Rectangle area = getClientArea();
+ graphics.drawLine(area.x, y, area.x + area.width, y);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/LifelineNodeFigure.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/LifelineNodeFigure.java
new file mode 100644
index 0000000000..6e94424495
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/LifelineNodeFigure.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.PositionConstants;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.OneLineMarginBorder;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.AnchorProvider;
+
+/**
+ * This specific figure overrides {@link SequenceNodeFigure} to draw a dash line
+ * over.
+ *
+ * @author smonnier
+ *
+ */
+public class LifelineNodeFigure extends SequenceNodeFigure {
+
+ /**
+ * Create a new {@link LifelineNodeFigure}.
+ *
+ * @param width
+ * the width.
+ * @param height
+ * the height.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public LifelineNodeFigure(int width, int height, AnchorProvider anchorProvider) {
+ super(width, height, anchorProvider);
+
+ OneLineMarginBorder oneLineBorder = new OneLineMarginBorder(PositionConstants.MIDDLE);
+ oneLineBorder.setStyle(Graphics.LINE_CUSTOM);
+ oneLineBorder.setLineDash(LayoutConstants.LIFELINE_DASH_STYLE);
+ setBorder(oneLineBorder);
+ }
+
+ /**
+ * This method is overridden to avoid drawing the border.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void paintClientArea(Graphics graphics) {
+ // Do nothing. This way the style edit part of the node will not be
+ // drawn. The lifeline is displayed using the OneLineDashborder, with
+ // middle position.
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/OperandFigure.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/OperandFigure.java
new file mode 100644
index 0000000000..7efa0acae7
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/OperandFigure.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+
+import org.eclipse.sirius.BackgroundStyle;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IContainerLabelOffsets;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.GradientRoundedRectangle;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.OneLineMarginBorder;
+
+/**
+ * Custom figure to paint only a bottom dash line instead of a full border.
+ *
+ * @author smonnier
+ */
+public class OperandFigure extends GradientRoundedRectangle {
+
+ private Operand operand;
+
+ /**
+ * Create a new {@link LifelineNodeFigure}.
+ *
+ * @param dimension
+ * dimension of the corner (with radius, height radius)
+ * @param backgroundStyle
+ * style of the wanted gradient
+ * @param operand
+ * the current operand
+ */
+ public OperandFigure(final Dimension dimension, final BackgroundStyle backgroundStyle, Operand operand) {
+ super(dimension, backgroundStyle);
+
+ this.operand = operand;
+
+ this.setFill(false);
+ this.setOutline(false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void createBorder() {
+ OneLineMarginBorder oneLineBorder = new OneLineMarginBorder(PositionConstants.BOTTOM);
+ oneLineBorder.setStyle(Graphics.LINE_CUSTOM);
+ oneLineBorder.setLineDash(LayoutConstants.OPERAND_DASH_STYLE);
+ oneLineBorder.setMargin(IContainerLabelOffsets.LABEL_OFFSET - 1, 0, 0, 0);
+
+ setBorder(oneLineBorder);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to paint only a bottom dash line instead of a full border.
+ */
+ @Override
+ protected void paintBorder(Graphics graphics) {
+ if (!isLastOperand()) {
+ super.paintBorder(graphics);
+ }
+ }
+
+ /**
+ * Check if it is the last operand. In that case we do not need to paint the
+ * operand separator.
+ */
+ private boolean isLastOperand() {
+ boolean isLast = false;
+ if (operand != null) {
+ isLast = operand.isLastOperand();
+ }
+ return isLast;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/RangeGuide.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/RangeGuide.java
new file mode 100644
index 0000000000..218ab8d574
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/RangeGuide.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * A rectangle across the whole diagram, useful as feedback for sequence
+ * diagrams where the vertical location of elements relative to each others is
+ * significant.
+ *
+ * @author mporhel
+ */
+public class RangeGuide extends Figure {
+ private final Range range;
+
+ /**
+ * Creates a feedback figure with two horizontal guide placed at the given
+ * range.
+ *
+ * @param color
+ * the color of the line.
+ * @param range
+ * the range of the guide.e wit
+ * @param fill
+ * fills the range with the same color, but lighter and
+ * transparent.
+ */
+ public RangeGuide(Color color, Range range, boolean fill) {
+ this.range = range;
+ setForegroundColor(color);
+ setBackgroundColor(color);
+ super.setOpaque(fill);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void paintFigure(Graphics graphics) {
+ Rectangle rect = getBounds().getCopy();
+ rect.y = range.getLowerBound();
+ rect.height = 1;
+
+ graphics.drawLine(rect.getTopLeft(), rect.getTopRight());
+
+ // if range have a null width, no need to fill it or to draw the bottom
+ // line.
+ // we have to reduce the height of the drawn rectangle to stay in the
+ // bounds of the figure.
+ if (range.width() > 1) {
+ rect.height = range.width() - 1;
+ graphics.drawLine(rect.getBottomLeft(), rect.getBottomRight());
+
+ if (super.isOpaque()) {
+ int alpha = graphics.getAlpha();
+ graphics.setAlpha(25);
+ graphics.fillRectangle(rect);
+ graphics.setAlpha(alpha);
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceMessageLabelLocator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceMessageLabelLocator.java
new file mode 100644
index 0000000000..99783c32d3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceMessageLabelLocator.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.figures.LabelLocator;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramEdgeEditPart.ViewEdgeFigure;
+
+/**
+ * Specific locator for sequence message to avoid vertical move of labels when
+ * lifelines are moved. (Avoid offset negation by GMF)
+ *
+ * @author mporhel
+ *
+ */
+public class SequenceMessageLabelLocator extends LabelLocator {
+
+ LabelLocator labelLocator;
+
+ /**
+ * Constructor for figure who are located and sized.
+ *
+ * @param parent
+ * the parent figure
+ * @param wrappedlocator
+ * default locator
+ */
+ public SequenceMessageLabelLocator(IFigure parent, LabelLocator wrappedlocator) {
+ super(parent, new Rectangle(wrappedlocator.getOffset(), wrappedlocator.getSize()), wrappedlocator.getAlignment());
+ Preconditions.checkNotNull(wrappedlocator);
+ this.labelLocator = wrappedlocator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void relocate(IFigure target) {
+ if (SequenceMessageLabelLocator.isRightToLeft((ViewEdgeFigure) target.getParent())) {
+ labelLocator.setOffset(getOffset().getCopy().negate());
+ }
+
+ labelLocator.relocate(target);
+ labelLocator.setOffset(getOffset());
+ }
+
+ /**
+ * Test if the given ViewEdgeFigure is from right to left.
+ *
+ * @param parent
+ * a ViewEdgeFigure
+ * @return true if the given connection figure has its first point on thr
+ * right of its left point.
+ */
+ public static boolean isRightToLeft(ViewEdgeFigure parent) {
+ if (parent != null) {
+ PointList points = parent.getPoints();
+ int fpX = points.getFirstPoint().x;
+ int lpX = points.getLastPoint().x;
+
+ return fpX > lpX;
+ }
+ return false;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceNodeFigure.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceNodeFigure.java
new file mode 100644
index 0000000000..56baa671bb
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceNodeFigure.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
+
+import org.eclipse.sirius.diagram.ui.tools.api.figure.AirDefaultSizeNodeFigure;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.AnchorProvider;
+
+/**
+ * This specific figure overrides {@link AirDefaultSizeNodeFigure} to create
+ * specific anchor.
+ *
+ * @author mporhel
+ *
+ */
+public class SequenceNodeFigure extends AirDefaultSizeNodeFigure {
+
+ /**
+ * Create a new {@link SequenceNodeFigure}.
+ *
+ * @param defSize
+ * the size.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public SequenceNodeFigure(final Dimension defSize, final AnchorProvider anchorProvider) {
+ super(defSize, anchorProvider);
+ }
+
+ /**
+ * Create a new {@link SequenceNodeFigure}.
+ *
+ * @param width
+ * the width.
+ * @param height
+ * the height.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public SequenceNodeFigure(final int width, final int height, final AnchorProvider anchorProvider) {
+ super(width, height, anchorProvider);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ConnectionAnchor createAnchor(PrecisionPoint p) {
+ return new SequenceSlidableAnchor(this, p);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ConnectionAnchor createDefaultAnchor() {
+ return new SequenceSlidableAnchor(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ConnectionAnchor getConnectionAnchor(final String terminal) {
+ ConnectionAnchor connectAnchor = super.getConnectionAnchor(terminal);
+ if (connectAnchor instanceof SequenceSlidableAnchor) {
+ ((SequenceSlidableAnchor) connectAnchor).updateCustomStatus(terminal);
+ }
+ return connectAnchor;
+ }
+
+ /**
+ * Returns a new anchor for this node figure.
+ *
+ * Handles sequence nodes with a 0 width and non 0 height (collapse) as if
+ * they have a 1 pixel width.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected ConnectionAnchor createConnectionAnchor(Point p) {
+ ConnectionAnchor anchor;
+
+ // Handle Sequence collapsed elements.
+ Rectangle bounds = getBounds().getCopy();
+ if (p != null && bounds.width == 0 && bounds.height != 0) {
+ bounds.width = 1;
+ Point temp = p.getCopy();
+ translateToRelative(temp);
+ PrecisionPoint pt = BaseSlidableAnchor.getAnchorRelativeLocation(temp, bounds);
+ if (isDefaultAnchorArea(pt)) {
+ anchor = getConnectionAnchor(szAnchor);
+ } else {
+ anchor = createAnchor(pt);
+ }
+ } else {
+ anchor = super.createConnectionAnchor(p);
+ }
+ return anchor;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceSlidableAnchor.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceSlidableAnchor.java
new file mode 100644
index 0000000000..86a8805086
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SequenceSlidableAnchor.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor;
+
+/**
+ * Specialized anchor with some customizations for sequence diagrams.
+ *
+ * @author mporhel
+ */
+public class SequenceSlidableAnchor extends SlidableAnchor {
+
+ boolean custom;
+
+ /**
+ * Constructor.
+ *
+ * @param owner
+ * the figure that this anchor is associated with..
+ */
+ public SequenceSlidableAnchor(IFigure owner) {
+ super(owner);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param owner
+ * the figure that this anchor is associated with.
+ * @param pp
+ * the PrecisionPoint that the anchor will initially attach to.
+ */
+ public SequenceSlidableAnchor(IFigure owner, PrecisionPoint pp) {
+ super(owner, pp);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param anchor
+ * .
+ * @param pp
+ * the PrecisionPoint that the anchor will initially attach to.
+ */
+ public SequenceSlidableAnchor(ConnectionAnchor anchor, PrecisionPoint pp) {
+ super(anchor.getOwner(), pp);
+ custom = true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Point getLocation(Point ownReference, Point foreignReference) {
+ Point location = ownReference.getCopy();
+
+ if (!custom) {
+ location = super.getLocation(ownReference, foreignReference);
+ }
+
+ return location;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTerminal() {
+ String terminal = super.getTerminal();
+ if (custom) {
+ terminal = terminal + " custom";
+ }
+ return terminal;
+ }
+
+ /**
+ * Parse ice information and set the corresponding location.
+ *
+ * @param terminal
+ * an anchor terminal id.
+ */
+ public void updateCustomStatus(String terminal) {
+ if (terminal.contains("custom")) {
+ custom = true;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SouthCenteredBorderItemLocator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SouthCenteredBorderItemLocator.java
new file mode 100644
index 0000000000..aae7c5a042
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/figure/SouthCenteredBorderItemLocator.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.CenteredBorderItemLocator;
+
+/**
+ * Specific locator for south centered figures. There is no possibility to
+ * change the side. The border item offset can be forced.
+ *
+ * @author mporhel
+ *
+ */
+public class SouthCenteredBorderItemLocator extends CenteredBorderItemLocator {
+
+ private final Dimension forcedBorderItemOffset;
+
+ /**
+ * Creates a new SouthCenteredBorderItemLocator with the specified
+ * parentFigure.
+ *
+ * @param parentFigure
+ * the parent figure
+ */
+ public SouthCenteredBorderItemLocator(IFigure parentFigure) {
+ this(parentFigure, null);
+ }
+
+ /**
+ * Creates a new SouthCenteredBorderItemLocator with the specified
+ * parentFigure.
+ *
+ * @param parentFigure
+ * the parent figure
+ * @param forcedBorderItemOffset
+ * unchangeable border item offset.
+ */
+ public SouthCenteredBorderItemLocator(IFigure parentFigure, Dimension forcedBorderItemOffset) {
+ super(parentFigure);
+ this.forcedBorderItemOffset = forcedBorderItemOffset;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator#setPreferredSideOfParent(int)
+ */
+ @Override
+ public void setPreferredSideOfParent(int preferredSide) {
+ super.setPreferredSideOfParent(PositionConstants.SOUTH);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator#setCurrentSideOfParent(int)
+ */
+ @Override
+ public void setCurrentSideOfParent(int side) {
+ super.setCurrentSideOfParent(PositionConstants.SOUTH);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void relocate(IFigure borderItem) {
+ super.relocate(borderItem);
+ unfix();
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator#setBorderItemOffset(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setBorderItemOffset(Dimension borderItemOffset) {
+ if (forcedBorderItemOffset != null) {
+ super.setBorderItemOffset(forcedBorderItemOffset);
+ } else {
+ super.setBorderItemOffset(borderItemOffset);
+
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CenteredBorderItemLocator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CenteredBorderItemLocator.java
new file mode 100644
index 0000000000..38b6084470
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CenteredBorderItemLocator.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator;
+
+/**
+ * Specific border item locator to keep the RootExecution always in the middle
+ * of the south face of an InstanceRole.
+ *
+ * @author smonnier
+ *
+ */
+public class CenteredBorderItemLocator extends DBorderItemLocator {
+
+ /**
+ * Create an {@link CenteredBorderItemLocator} with the specified
+ * parentFigure.
+ *
+ * @param parentFigure
+ * the parent figure.
+ */
+ public CenteredBorderItemLocator(final IFigure parentFigure) {
+ super(parentFigure);
+ }
+
+ /**
+ * Create a {@link CenteredBorderItemLocator} with the specified item,
+ * parentFigure and constraint.
+ *
+ * @param borderItem
+ * the border item.
+ * @param parentFigure
+ * the parent figure.
+ * @param constraint
+ * the constraint.
+ */
+ public CenteredBorderItemLocator(final IFigure borderItem, final IFigure parentFigure, final Rectangle constraint) {
+ super(borderItem, parentFigure, constraint);
+ }
+
+ /**
+ * Create a {@link CenteredBorderItemLocator} with the specified item and
+ * preferredSide.
+ *
+ * @param parentFigure
+ * the parent figure.
+ * @param preferredSide
+ * the preferred side.
+ */
+ public CenteredBorderItemLocator(final IFigure parentFigure, final int preferredSide) {
+ super(parentFigure, preferredSide);
+ }
+
+ /**
+ * Get the preferred location. This method is overridden to set the position
+ * of the border item in the middle of the south border.
+ *
+ * @param borderItem
+ * the border item
+ * @return point
+ */
+ @Override
+ protected Point getPreferredLocation(IFigure borderItem) {
+ Point setFigurePosition = setFigurePosition(borderItem, super.getPreferredLocation(borderItem));
+ if (setFigurePosition != null) {
+ return setFigurePosition;
+ }
+ return super.getPreferredLocation(borderItem);
+ }
+
+ /**
+ * Calculate the position of the middle of the south border.
+ *
+ * @param borderItem
+ * the border item figure
+ * @param borderItemPoint
+ * the super getPreferredLocation result that return the south
+ * west corner.
+ * @return the position where to set the root execution bordered node
+ */
+ private Point setFigurePosition(IFigure borderItem, Point borderItemPoint) {
+ Rectangle parentBorder = getParentBorder();
+ if (parentBorder != null) {
+ Rectangle executionFigureBounds = borderItem.getBounds();
+ return new Point(parentBorder.x + parentBorder.width / 2 - executionFigureBounds.width / 2, borderItemPoint.y);
+ }
+ return null;
+ }
+
+ /**
+ * This method is overridden to keep the calculated center in
+ * setFigurePosition method, even if the bordered node is larger than its
+ * parent. As instance, the Destroy End node can be larger that its parent
+ * lifeline.
+ *
+ * {@inheritDoc}
+ *
+ * @param suggestedLocation
+ * suggested location
+ * @param suggestedSide
+ * suggested side
+ * @param borderItem
+ * the border item.
+ * @return point the location point
+ */
+ @Override
+ protected Point locateOnParent(Point suggestedLocation, int suggestedSide, IFigure borderItem) {
+ return new Point(suggestedLocation.x, super.locateOnParent(suggestedLocation, suggestedSide, borderItem).y);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CombinedFragmentVerticalPositionFunction.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CombinedFragmentVerticalPositionFunction.java
new file mode 100644
index 0000000000..50e0158b02
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/CombinedFragmentVerticalPositionFunction.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Function;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+
+/**
+ * A function which computes the vertical position (in absolute, normalized
+ * coordinates) of an
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentEditPart}
+ * .
+ *
+ * @author smonnier
+ */
+public class CombinedFragmentVerticalPositionFunction implements Function<IGraphicalEditPart, Integer> {
+ /**
+ * The value returned by the function to indicate an invalid input from
+ * which a position can not be determined.
+ */
+ public static final int INVALID_POSITION = 0;
+
+ /**
+ * Constructor.
+ *
+ */
+ public CombinedFragmentVerticalPositionFunction() {
+ }
+
+ /**
+ * Returns the vertical position of the specified InteractionUseEditPart as
+ * it appears on the diagram associated to this function.
+ *
+ * @param graphicalEditPart
+ * the CombinedFragmentEditPart for which to compute the
+ * position.
+ * @return the vertical position of the end, or
+ * <code>INVALID_POSITION</code>.
+ */
+ public Integer apply(IGraphicalEditPart graphicalEditPart) {
+ Option<CombinedFragment> combinedFragment = ISequenceElementAccessor.getCombinedFragment(graphicalEditPart.getNotationView());
+ if (combinedFragment.some()) {
+ return combinedFragment.get().getVerticalRange().getLowerBound();
+ } else {
+ return INVALID_POSITION;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/InstanceUseVerticalPositionFunction.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/InstanceUseVerticalPositionFunction.java
new file mode 100644
index 0000000000..db31c68365
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/InstanceUseVerticalPositionFunction.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Function;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+
+/**
+ * A function which computes the vertical position (in absolute, normalized
+ * coordinates) of an
+ * {@link org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InteractionUseEditPart}
+ * .
+ *
+ * @author smonnier
+ */
+public class InstanceUseVerticalPositionFunction implements Function<IGraphicalEditPart, Integer> {
+ /**
+ * The value returned by the function to indicate an invalid input from
+ * which a position can not be determined.
+ */
+ public static final int INVALID_POSITION = 0;
+
+ /**
+ * Constructor.
+ *
+ */
+ public InstanceUseVerticalPositionFunction() {
+ }
+
+ /**
+ * Returns the vertical position of the specified InteractionUseEditPart as
+ * it appears on the diagram associated to this function.
+ *
+ * @param graphicalEditPart
+ * the InteractionUseEditPart for which to compute the position.
+ * @return the vertical position of the end, or
+ * <code>INVALID_POSITION</code>.
+ */
+ public Integer apply(IGraphicalEditPart graphicalEditPart) {
+ Option<InteractionUse> interactionUse = ISequenceElementAccessor.getInteractionUse(graphicalEditPart.getNotationView());
+ if (interactionUse.some()) {
+ return interactionUse.get().getVerticalRange().getLowerBound();
+ } else {
+ return INVALID_POSITION;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/LayoutEditPartConstants.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/LayoutEditPartConstants.java
new file mode 100644
index 0000000000..4e479b6fd0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/LayoutEditPartConstants.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+
+/**
+ * A utility class to centralize all the dimensions ("magic number") used during
+ * the layout of sequence diagrams. Unless otherwise stated, all the dimensions
+ * and locations are in pixels.
+ *
+ * @author mporhel
+ */
+public final class LayoutEditPartConstants {
+
+ /**
+ * How much an EndOfLife overlaps its parent lifeline.
+ */
+ public static final Dimension EOL_BORDER_ITEM_OFFSET = new Dimension(0, 0);
+
+ /**
+ * Which side of its parent should an EndOfLife appear on.
+ */
+ public static final int EOL_SIDE = PositionConstants.SOUTH;
+
+ /**
+ * How much an execution overlaps its parent execution.
+ */
+ public static final Dimension EXECUTION_BORDER_ITEM_OFFSET = new Dimension(5, 0);
+
+ /**
+ * Which side of its parent should an execution appear on.
+ */
+ public static final int EXECUTION_SIDE = PositionConstants.EAST;
+
+ /**
+ * How much a root execution overlaps its parent instance role.
+ */
+ public static final Dimension ROOT_EXECUTION_BORDER_ITEM_OFFSET = new Dimension(0, 0);
+
+ private LayoutEditPartConstants() {
+ // Prevents instantiation.
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceGraphicalHelper.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceGraphicalHelper.java
new file mode 100644
index 0000000000..b8d492eae9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceGraphicalHelper.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+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.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.VerticalPositionFunction;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IBorderItemOffsets;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.util.GMFNotationHelper;
+
+/**
+ * Utility class to collect helper methods which deal with GraphicalOrdering but
+ * which are not part of its API.
+ *
+ * @author pcdavid
+ */
+public final class SequenceGraphicalHelper {
+ private SequenceGraphicalHelper() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Finds and returns the EventEnd which corresponds to the first event
+ * graphically above the specified Y coordinate in a diagram.
+ *
+ * @param diagram
+ * the diagram.
+ * @param y
+ * the Y coordinate (in logical space)
+ * @return the EventEnd which corresponds to the first event above Y.
+ */
+ public static EventEnd getEndBefore(SequenceDDiagram diagram, int y) {
+ VerticalPositionFunction vpf = new VerticalPositionFunction(diagram);
+ for (EventEnd end : Lists.reverse(diagram.getGraphicalOrdering().getEventEnds())) {
+ int pos = vpf.apply(end);
+ if (pos != VerticalPositionFunction.INVALID_POSITION && pos <= y) {
+ return end;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds and returns the InstanceRole semantic element which corresponds to
+ * the first element graphically above the specified X coordinate in a
+ * diagram.
+ *
+ * @param diagram
+ * the diagram.
+ * @param x
+ * the X coordinate (in logical space)
+ * @return the element which corresponds to the first InstanceRole above X.
+ */
+ public static EObject getInstanceRoleBefore(SequenceDDiagram diagram, int x) {
+ Iterable<Diagram> diagramViews = Iterables.filter(ISequenceElementAccessor.getViewsForSemanticElement(diagram, diagram.getTarget()), Diagram.class);
+ if (!Iterables.isEmpty(diagramViews)) {
+ Option<SequenceDiagram> seqDiag = ISequenceElementAccessor.getSequenceDiagram(diagramViews.iterator().next());
+ if (seqDiag.some()) {
+ for (InstanceRole ir : Lists.reverse(seqDiag.get().getSortedInstanceRole())) {
+ int pos = ir.getProperLogicalBounds().x;
+ if (pos <= x) {
+ return ir.getSemanticTargetElement().get();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds and returns the EventEnd which corresponds to the first event
+ * graphically below the specified Y coordinate in a diagram.
+ *
+ * @param diagram
+ * the diagram.
+ * @param y
+ * the Y coordinate
+ * @return the EventEnd which corresponds to the first event below Y.
+ */
+ public static EventEnd getEndAfter(SequenceDDiagram diagram, int y) {
+ VerticalPositionFunction vpf = new VerticalPositionFunction(diagram);
+ for (EventEnd end : diagram.getGraphicalOrdering().getEventEnds()) {
+ int pos = vpf.apply(end);
+ if (pos != VerticalPositionFunction.INVALID_POSITION && pos > y) {
+ return end;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the normalized Y location of the Center of an edit part, using
+ * only information from the GMF model (not Draw2D figures).
+ *
+ * @param part
+ * the edit part.
+ * @return the absolute, normalized Y location of the Center of the
+ * DNodeEditPart.
+ */
+ public static int getAbsoluteYCenterFromGMFView(IGraphicalEditPart part) {
+ if (part instanceof ShapeNodeEditPart) {
+ Rectangle absoluteboundsRectangle = SequenceGraphicalHelper.getAbsoluteBoundsFromGMFView(part);
+ return absoluteboundsRectangle.getCenter().y;
+ }
+ // FIXME This uses Draw2D info
+ Point location = part.getFigure().getBounds().getCenter().getCopy();
+ GraphicalHelper.screen2logical(location, part);
+ return location.y;
+ }
+
+ /**
+ * Returns the normalized Y location of the Center of an edit part, using
+ * only information from the GMF model (not Draw2D figures).
+ *
+ * Use information from the GMF Notation model if available (which is most
+ * of the time), and fall back to the Draw2D Figure's bounds otherwise. The
+ * figure's bounds is always available, but depending on the time of the
+ * call it may be out of date (pending a revalidate/repaint).
+ *
+ * @param part
+ * the edit part
+ *
+ * @return the absolute normalized bounds of the ISequenceEvent edit part
+ */
+ public static Rectangle getAbsoluteBoundsFromGMFView(IGraphicalEditPart part) {
+ Rectangle rect;
+
+ /*
+ * Initialize with Draw2D information. May be out of date under some
+ * conditions.
+ */
+ rect = part.getFigure().getBounds().getCopy();
+ if (part instanceof LifelineEditPart) {
+ SequenceGraphicalHelper.handleLifelineEditPartOffset(rect);
+ }
+
+ /*
+ * Handle Node case with Notation information
+ */
+ if (part.getNotationView() instanceof Node) {
+ Node node = (Node) part.getNotationView();
+ Point absLoc = GMFNotationHelper.getAbsoluteLocation(node);
+
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ Bounds bounds = (Bounds) layoutConstraint;
+ rect.setLocation(absLoc.x, absLoc.y);
+
+ // prevent auto size
+ if (bounds.getWidth() != -1) {
+ rect.width = bounds.getWidth();
+ }
+
+ // prevent auto size
+ if (bounds.getHeight() != -1) {
+ rect.height = bounds.getHeight();
+ }
+
+ if (!(part instanceof InstanceRoleEditPart)) {
+ SequenceGraphicalHelper.handleLifelineEditPartOffset(rect);
+ }
+ }
+ }
+
+ return rect;
+ }
+
+ private static void handleLifelineEditPartOffset(Rectangle rect) {
+ // FIXME LifelineEditPart are placed with offset which did
+ // not appear in GMF model
+ rect.translate(0, IBorderItemOffsets.DEFAULT_OFFSET.height);
+ }
+
+ /**
+ * Return the absolute anchor position for the given range and anchor.
+ *
+ * @param anchor
+ * the current anchor.
+ * @param range
+ * range of the ISequenceEvent which supports the anchor.
+ * @return the absolute anchor position.
+ */
+ public static int getAnchorAbsolutePosition(IdentityAnchor anchor, Range range) {
+ PrecisionPoint rel = anchor != null ? BaseSlidableAnchor.parseTerminalString(anchor.getId()) : new PrecisionPoint(0.5, 0.5);
+ return range.getLowerBound() + (int) Math.round(rel.preciseY * range.width());
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceLayoutProvider.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceLayoutProvider.java
new file mode 100644
index 0000000000..e4680788ad
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceLayoutProvider.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshGraphicalOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.RefreshSemanticOrderingsOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SynchronizeGraphicalOrderingOperation;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.tools.api.command.DoNothingCommand;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.util.EditPartTools;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * The layout provider for sequence diagrams.
+ *
+ * @author ymortier, mporhel
+ */
+public class SequenceLayoutProvider extends AbstractLayoutProvider {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command layoutEditParts(@SuppressWarnings("rawtypes") List selectedObjects, IAdaptable layoutHint) {
+ SequenceDiagramEditPart sdep = getParentSequenceDiagramEditPart(selectedObjects);
+ boolean isArrangeAll = isArrangeAll(sdep, selectedObjects);
+ if (sdep != null && isArrangeAll) {
+ return createArrangeAllCommand(sdep);
+ } else {
+ return DoNothingCommand.INSTANCE;
+ }
+ }
+
+ private boolean isArrangeAll(SequenceDiagramEditPart sdep, List selectedObjects) {
+ boolean result = false;
+ if (sdep != null && selectedObjects != null) {
+ result = sdep.getChildren().size() == selectedObjects.size() && sdep.getChildren().containsAll(selectedObjects);
+ }
+ return result;
+ }
+
+ private Command createArrangeAllCommand(SequenceDiagramEditPart sdep) {
+ TransactionalEditingDomain transactionalEditingDomain = sdep.getEditingDomain();
+ SequenceDiagram sequenceDiagram = sdep.getSequenceDiagram();
+ SequenceDDiagram sequenceDDiagram = (SequenceDDiagram) sdep.resolveSemanticElement();
+ Collection<AbstractModelChangeOperation<Void>> operations = new ArrayList<AbstractModelChangeOperation<Void>>();
+
+ operations.add(new RefreshGraphicalOrderingOperation(sequenceDiagram));
+ operations.add(new RefreshSemanticOrderingsOperation(sequenceDDiagram));
+ operations.add(new SynchronizeGraphicalOrderingOperation(sdep.getDiagramView(), true));
+
+ ICommand cmd = CommandFactory.createICommand(transactionalEditingDomain, operations);
+ cmd.setLabel("Arrange all");
+
+ return new ICommandProxy(cmd);
+ }
+
+ private SequenceDiagramEditPart getParentSequenceDiagramEditPart(List<?> selectedObjects) {
+ if (!selectedObjects.isEmpty()) {
+ return EditPartTools.getParentOfType((EditPart) selectedObjects.iterator().next(), SequenceDiagramEditPart.class);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceMessagesRouter.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceMessagesRouter.java
new file mode 100644
index 0000000000..569c951b07
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceMessagesRouter.java
@@ -0,0 +1,436 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.draw2d.AbsoluteBendpoint;
+import org.eclipse.draw2d.AbstractRouter;
+import org.eclipse.draw2d.Bendpoint;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.ConnectionRouter;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramEdgeEditPart;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.EndOfLifeEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.figure.LifelineNodeFigure;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * A specific router for the messages on a sequence diagram.
+ *
+ * @author pcdavid
+ */
+public class SequenceMessagesRouter extends AbstractRouter implements ConnectionRouter {
+
+ /**
+ * A point, reused for computations to avoid creating many instances.
+ */
+ private static final PrecisionPoint A_POINT = new PrecisionPoint();
+
+ /**
+ * The constraints associated to each connection to route.
+ */
+ private Map<Connection, Object> constraints = new WeakHashMap<Connection, Object>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setConstraint(Connection connection, Object constraint) {
+ this.constraints.put(connection, constraint);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getConstraint(Connection connection) {
+ return this.constraints.get(connection);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void remove(Connection connection) {
+ this.constraints.remove(connection);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void route(Connection conn) {
+ if (!isValidConnection(conn)) {
+ return;
+ }
+
+ List<Bendpoint> bendpoints = getRefreshedConstraint(conn);
+
+ IGraphicalEditPart part = null;
+ if (conn instanceof AbstractDiagramEdgeEditPart.ViewEdgeFigure) {
+ part = ((AbstractDiagramEdgeEditPart.ViewEdgeFigure) conn).getEditPart();
+ }
+
+ Point sourceRef = getReferencePoint(conn, true, bendpoints);
+ Point targetRef = getReferencePoint(conn, false, bendpoints);
+
+ boolean leftToRight = conn.getSourceAnchor().getReferencePoint().x < conn.getTargetAnchor().getReferencePoint().x;
+ boolean msgToSelf = sourceRef.x == targetRef.x && sourceRef.y != targetRef.y || bendpoints.size() >= 4;
+ msgToSelf = msgToSelf || isReflectiveMessage(part);
+
+ Rectangle sourceOwnerBounds = getAnchorOwnerBounds(conn.getSourceAnchor());
+ Rectangle targetOwnerBounds = getAnchorOwnerBounds(conn.getTargetAnchor());
+
+ sourceRef.x = getRefX(true, leftToRight, msgToSelf, sourceOwnerBounds, conn.getSourceAnchor().getOwner());
+ targetRef.x = getRefX(false, leftToRight, msgToSelf, targetOwnerBounds, conn.getTargetAnchor().getOwner());
+
+ PointList points = new PointList(Math.max(2, bendpoints.size()));
+
+ if (msgToSelf) {
+ // We are working on a message to self
+ // We align the 2 extra bendpoint with the relative source and
+ // target
+ Point secondPoint = sourceRef.getCopy();
+ Point thirdPoint = targetRef.getCopy();
+ double zoom = part == null ? 1.0 : GraphicalHelper.getZoom(part);
+
+ int hGap = LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_HORIZONTAL_GAP;
+ if (part instanceof SequenceMessageEditPart) {
+ Message msg = (Message) ((SequenceMessageEditPart) part).getISequenceEvent();
+ if (msg.isReflective()) {
+ hGap = msg.getReflexiveMessageWidth();
+ }
+ }
+
+ secondPoint.x = Math.max(sourceRef.x, targetRef.x) + (int) (hGap * zoom);
+ thirdPoint.x = secondPoint.x;
+
+ conn.translateToRelative(sourceRef);
+ conn.translateToRelative(secondPoint);
+ conn.translateToRelative(thirdPoint);
+
+ points.addPoint(sourceRef);
+ points.addPoint(secondPoint);
+ points.addPoint(thirdPoint);
+ } else {
+ conn.translateToRelative(sourceRef);
+ points.addPoint(sourceRef);
+ }
+ conn.translateToRelative(targetRef);
+ points.addPoint(targetRef);
+ conn.setPoints(points);
+
+ // This specific update have no use anymore and there was a problem with
+ // reflexive sync call and scroll
+ // updateEdgeBendpointOnMessageToSelfCreation(part, conn);
+ }
+
+ private int getRefX(boolean source, boolean leftToRight, boolean msgToSelf, Rectangle anchorOwnerBounds, IFigure anchorOwner) {
+ int refX;
+ boolean onLeft = (source && !leftToRight) || (leftToRight && !source);
+ onLeft = onLeft && !msgToSelf;
+
+ if (msgToSelf) { // bendpoints.size() >= 4 ||
+ // Source and Target of message to self are on the right
+ refX = anchorOwnerBounds.getRight().x;
+ } else {
+ refX = onLeft ? anchorOwnerBounds.getLeft().x : anchorOwnerBounds.getRight().x;
+ }
+
+ // Corrects figure for messages linked to lifelines (gap between line
+ // and real figure)
+ if (anchorOwner instanceof LifelineNodeFigure) {
+ LifelineNodeFigure lnf = (LifelineNodeFigure) anchorOwner;
+ int refMidWidth = (anchorOwnerBounds.width - lnf.getLineWidth()) / 2;
+ refX += onLeft ? refMidWidth : -refMidWidth;
+ }
+ return refX;
+ }
+
+ private Point getReferencePoint(Connection conn, boolean source, List<Bendpoint> bendpoints) {
+ Point ref;
+ if (bendpoints.isEmpty()) {
+ ConnectionAnchor anchor = source ? conn.getSourceAnchor() : conn.getTargetAnchor();
+ ref = anchor.getReferencePoint().getCopy();
+ } else {
+ int index = source ? 0 : bendpoints.size() - 1;
+ ref = new Point((bendpoints.get(index)).getLocation());
+ conn.translateToAbsolute(ref);
+ }
+ return ref;
+ }
+
+ private Rectangle getAnchorOwnerBounds(ConnectionAnchor anchor) {
+ Rectangle ownerBounds = anchor.getOwner().getBounds().getCopy();
+ anchor.getOwner().getParent().translateToAbsolute(ownerBounds);
+ return ownerBounds;
+ }
+
+ private boolean isReflectiveMessage(IGraphicalEditPart part) {
+ if (part instanceof SequenceMessageEditPart) {
+ ISequenceEvent ise = ((SequenceMessageEditPart) part).getISequenceEvent();
+ return ise instanceof Message && ((Message) ise).isReflective();
+ }
+ return false;
+ }
+
+ private List<Bendpoint> getRefreshedConstraint(Connection conn) {
+ boolean noBendpointsAtbeginning = false;
+ @SuppressWarnings("unchecked")
+ List<Bendpoint> bendpoints = (List<Bendpoint>) getConstraint(conn);
+ if (bendpoints == null) {
+ noBendpointsAtbeginning = true;
+ bendpoints = Collections.emptyList();
+ }
+ refreshBendpoints(bendpoints, conn);
+
+ if (!(noBendpointsAtbeginning && Collections.emptyList().equals(bendpoints))) {
+ // There is no need to set constraint if there is no bendpoints at
+ // the beginning of this method and that is finally empty.
+ setConstraint(conn, bendpoints);
+ }
+ return bendpoints;
+ }
+
+ private boolean isValidConnection(Connection conn) {
+ return isValidAnchor(conn.getSourceAnchor()) && isValidAnchor(conn.getTargetAnchor());
+ }
+
+ private boolean isValidAnchor(ConnectionAnchor anchor) {
+ return anchor != null && anchor.getOwner() != null;
+ }
+
+ private void refreshBendpoints(List<Bendpoint> bendpoints, Connection conn) {
+
+ IGraphicalEditPart part = null;
+ if (conn instanceof AbstractDiagramEdgeEditPart.ViewEdgeFigure) {
+ part = ((AbstractDiagramEdgeEditPart.ViewEdgeFigure) conn).getEditPart();
+ }
+ if (bendpoints.size() > 2) {
+ if (isReflectiveMessage(part)) {
+ if (bendpoints.size() > 4) {
+ // The user want to resize a message to self by pulling an
+ // edge (between bendpoints)
+ // This has the effect to add a fifth bendpoint
+ align5BendpointsOfMessageToSelf(bendpoints, conn);
+ } else if (bendpoints.size() == 4) {
+ // The user want to resize a message to self by pulling a
+ // bendpoint
+ align4BendpointsOfMessageToSelf(bendpoints, conn);
+ }
+ } else {
+ /*
+ * The only case where we have more than two bendpoints is when
+ * the user has dragged a connection, which created a temporary
+ * intermediate bendpoint. We use that new point as the
+ * reference Y coordinate for the start and end points, but
+ * remove the intermediate bendpoint itself.
+ */
+ Bendpoint start = bendpoints.get(0);
+ Bendpoint end = bendpoints.get(bendpoints.size() - 1);
+ Bendpoint moveRef = bendpoints.get(1);
+ bendpoints.clear();
+
+ A_POINT.setLocation(start.getLocation());
+ A_POINT.y = moveRef.getLocation().y;
+ Bendpoint newStart = new AbsoluteBendpoint(A_POINT);
+ bendpoints.add(newStart);
+ /*
+ * I don't understand exactly why, but the intermediate point
+ * must be kept here, otherwise the edges can only be moved of a
+ * very small vertical distance at a time.
+ */
+ bendpoints.add(moveRef);
+ A_POINT.setLocation(end.getLocation());
+ A_POINT.y = moveRef.getLocation().y;
+ Bendpoint newEnd = new AbsoluteBendpoint(A_POINT);
+ bendpoints.add(newEnd);
+ }
+ } else if (bendpoints.size() == 2) {
+ Bendpoint start = bendpoints.get(0);
+ Bendpoint end = bendpoints.get(bendpoints.size() - 1);
+
+ bendpoints.clear();
+ Bendpoint newStart = new AbsoluteBendpoint(start.getLocation());
+ Bendpoint newEnd = new AbsoluteBendpoint(end.getLocation());
+
+ if (isReflectiveMessage(part)) {
+ bendpoints.addAll(createMessageToSelf(start, end, (SequenceMessageEditPart) part));
+ } else {
+ if (part instanceof SequenceMessageEditPart
+ && (((SequenceMessageEditPart) part).getTarget() instanceof InstanceRoleEditPart || ((SequenceMessageEditPart) part).getTarget() instanceof EndOfLifeEditPart)) {
+ IGraphicalEditPart target = (IGraphicalEditPart) ((SequenceMessageEditPart) part).getTarget();
+ Rectangle targetBounds = target.getFigure().getBounds();
+ int yCenterPosition = targetBounds.y + targetBounds.height / 2;
+ newStart.getLocation().y = yCenterPosition;
+ }
+
+ bendpoints.add(newStart);
+ // Ensure the message is horizontal.
+ newEnd.getLocation().y = newStart.getLocation().y;
+ bendpoints.add(newEnd);
+ }
+ }
+ }
+
+ /**
+ * Having a connection with 5 bendpoints means that we are working on a
+ * message to self. We will compare the positions of the bendpoints with the
+ * previous ones. This way, we will know if the user has pulled a bendpoint
+ * and will move the other closest bendpoints to keep the layout.
+ *
+ * @param bendpoints
+ * the list of bendpoints on a connection
+ * @param conn
+ * the message to self connection
+ */
+ private void align4BendpointsOfMessageToSelf(final List<Bendpoint> bendpoints, Connection conn) {
+
+ Bendpoint newStart = new AbsoluteBendpoint(bendpoints.get(0).getLocation());
+ Bendpoint newSecondPoint = new AbsoluteBendpoint(bendpoints.get(1).getLocation());
+ Bendpoint newThirdPoint = new AbsoluteBendpoint(bendpoints.get(2).getLocation());
+ Bendpoint newEnd = new AbsoluteBendpoint(bendpoints.get(3).getLocation());
+ bendpoints.clear();
+
+ Bendpoint oldSecondPoint;
+ Bendpoint oldThirdPoint;
+ if (conn.getPoints() != null && conn.getPoints().size() == 4) {
+ oldSecondPoint = new AbsoluteBendpoint(conn.getPoints().getPoint(1));
+ oldThirdPoint = new AbsoluteBendpoint(conn.getPoints().getPoint(2));
+ } else {
+ oldSecondPoint = newSecondPoint;
+ oldThirdPoint = newThirdPoint;
+ }
+
+ if (oldSecondPoint.getLocation().y != newSecondPoint.getLocation().y) {
+ // Second point Y position has changed. We need to update the start
+ // point.
+ if (newSecondPoint.getLocation().y > newThirdPoint.getLocation().y - LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP) {
+ // limit vertical move to keep the minimum distance
+ newSecondPoint.getLocation().y = newThirdPoint.getLocation().y - LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ }
+ newStart.getLocation().y = newSecondPoint.getLocation().y;
+ }
+
+ if (oldThirdPoint.getLocation().y != newThirdPoint.getLocation().y) {
+ // Second point Y position has changed. We need to update the start
+ // point.
+ if (newThirdPoint.getLocation().y < newSecondPoint.getLocation().y + LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP) {
+ // limit vertical move to keep the minimum distance
+ newThirdPoint.getLocation().y = newSecondPoint.getLocation().y + LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ }
+ newEnd.getLocation().y = newThirdPoint.getLocation().y;
+ }
+
+ bendpoints.add(newStart);
+ bendpoints.add(newSecondPoint);
+ bendpoints.add(newThirdPoint);
+ bendpoints.add(newEnd);
+ }
+
+ /**
+ * Having a connection with 5 bendpoints means that we are working on a
+ * message to self that the user is resizing by pulling an edge between 2
+ * bendpoints. In that case we will align the bendpoints just before and
+ * after to keep the same layout.
+ *
+ * @param bendpoints
+ * the list of bendpoints on a connection
+ * @param conn
+ * the message to self connection
+ */
+ private void align5BendpointsOfMessageToSelf(final List<Bendpoint> bendpoints, Connection conn) {
+
+ Bendpoint newStart = new AbsoluteBendpoint(bendpoints.get(0).getLocation());
+ Bendpoint secondPoint = new AbsoluteBendpoint(bendpoints.get(1).getLocation());
+ Bendpoint thirdPoint = new AbsoluteBendpoint(bendpoints.get(2).getLocation());
+ Bendpoint fourthPoint = new AbsoluteBendpoint(bendpoints.get(3).getLocation());
+ Bendpoint newEnd = new AbsoluteBendpoint(bendpoints.get(4).getLocation());
+ bendpoints.clear();
+
+ Bendpoint oldSecondPoint = new AbsoluteBendpoint(conn.getPoints().getPoint(1));
+ Bendpoint oldThirdPoint = new AbsoluteBendpoint(conn.getPoints().getPoint(2));
+
+ if (oldSecondPoint.getLocation().y != secondPoint.getLocation().y) {
+ // The new bendpoint is between old start and old second points
+ if (secondPoint.getLocation().y > oldThirdPoint.getLocation().y - LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP) {
+ // limit vertical move to keep the minimum distance
+ secondPoint.getLocation().y = oldThirdPoint.getLocation().y - LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ }
+ newStart.getLocation().y = secondPoint.getLocation().y;
+ thirdPoint.getLocation().y = secondPoint.getLocation().y;
+ } else if (oldThirdPoint.getLocation().y != fourthPoint.getLocation().y) {
+
+ // The new bendpoint is between old third and old end points
+ if (fourthPoint.getLocation().y < oldSecondPoint.getLocation().y + LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP) {
+ // limit vertical move to keep the minimum distance
+ fourthPoint.getLocation().y = oldSecondPoint.getLocation().y + LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ }
+ thirdPoint.getLocation().y = fourthPoint.getLocation().y;
+ newEnd.getLocation().y = fourthPoint.getLocation().y;
+ }
+
+ bendpoints.add(newStart);
+ bendpoints.add(secondPoint);
+ bendpoints.add(thirdPoint);
+ bendpoints.add(fourthPoint);
+ bendpoints.add(newEnd);
+ }
+
+ /**
+ * Creates a message to self from start to end by adding 2 bendpoints
+ * shifted on the right by LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_GAP.
+ *
+ * @param start
+ * the message to self start position
+ * @param end
+ * the message to self end position
+ * @return the list of bendpoints to create a message to self from start to
+ * end
+ */
+ private List<Bendpoint> createMessageToSelf(Bendpoint start, Bendpoint end, SequenceMessageEditPart part) {
+ ArrayList<Bendpoint> messageToSelfBendpoint = new ArrayList<Bendpoint>();
+
+ Bendpoint newStart = new AbsoluteBendpoint(start.getLocation());
+ Bendpoint newSecondPoint = new AbsoluteBendpoint(start.getLocation());
+ Bendpoint newThirdPoint = new AbsoluteBendpoint(end.getLocation());
+ Bendpoint newEnd = new AbsoluteBendpoint(end.getLocation());
+
+ int minGap = LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ if (newEnd.getLocation().y - newStart.getLocation().y < minGap) {
+ newThirdPoint.getLocation().y = newStart.getLocation().y + minGap;
+ newEnd.getLocation().y = newThirdPoint.getLocation().y;
+ }
+
+ messageToSelfBendpoint.add(newStart);
+ messageToSelfBendpoint.add(newSecondPoint);
+ messageToSelfBendpoint.add(newThirdPoint);
+ messageToSelfBendpoint.add(newEnd);
+
+ return messageToSelfBendpoint;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceZOrderingRefresher.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceZOrderingRefresher.java
new file mode 100644
index 0000000000..9503b906ad
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/layout/SequenceZOrderingRefresher.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InteractionUseEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ObservationPointEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+
+/**
+ * Refreshes the Z-ordering in which interaction uses and combined fragments
+ * appear on a diagram.
+ *
+ * @author smonnier
+ */
+public class SequenceZOrderingRefresher implements Runnable {
+ private final SequenceDiagramEditPart sequenceDiagramPart;
+
+ /**
+ * Creates a command which updates the Z ordering of interaction uses and
+ * combined fragments.
+ *
+ * @param sequenceDiagramEditPart
+ * the diagram whose interaction uses and combined fragments Z
+ * ordering should be refreshed.
+ */
+ public SequenceZOrderingRefresher(SequenceDiagramEditPart sequenceDiagramEditPart) {
+ this.sequenceDiagramPart = Preconditions.checkNotNull(sequenceDiagramEditPart);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ moveInteractionUsesToFront();
+ moveCombinedFragmentsToBack();
+ moveObservationPointToFront();
+ }
+
+ /**
+ * Shift the interaction uses before every other children so they appear
+ * visually in front of the rest.
+ */
+ private void moveInteractionUsesToFront() {
+ moveParts(InteractionUseEditPart.class, true, new InstanceUseVerticalPositionFunction());
+ }
+
+ /**
+ * Shift the interaction uses before every other children so they appear
+ * visually in front of the rest.
+ */
+ private void moveObservationPointToFront() {
+ moveParts(ObservationPointEditPart.class, true, null);
+ }
+
+ /**
+ * Shift the combined fragments before every other children so they appear
+ * visually behind the rest.
+ */
+ private void moveCombinedFragmentsToBack() {
+ moveParts(CombinedFragmentEditPart.class, false, new CombinedFragmentVerticalPositionFunction());
+ }
+
+ /**
+ * Filter the diagram children parts with type to move. Sort them with the
+ * sorter if not null. Reverse the result if move to front.
+ */
+ private void moveParts(Class<? extends IGraphicalEditPart> typeToMove, boolean moveToFront, Function<IGraphicalEditPart, Integer> sorter) {
+ List<? extends IGraphicalEditPart> partsToMove = Lists.newArrayList(Iterables.filter(sequenceDiagramPart.getChildren(), typeToMove));
+
+ if (sorter != null) {
+ Ordering<IGraphicalEditPart> onResultOf = Ordering.natural().onResultOf(sorter);
+ if (moveToFront) {
+ onResultOf = onResultOf.reverse();
+ }
+ Collections.sort(partsToMove, onResultOf);
+ }
+
+ // Bring combined fragments to back/front
+ if (!partsToMove.isEmpty()) {
+ int index = moveToFront ? Iterables.size(Iterables.filter(sequenceDiagramPart.getChildren(), IGraphicalEditPart.class)) - 1 : 0;
+ for (IGraphicalEditPart frame : partsToMove) {
+ sequenceDiagramPart.reorderChild(frame, index);
+ index = index + (moveToFront ? -1 : 1);
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramEditPartProvider.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramEditPartProvider.java
new file mode 100644
index 0000000000..0648ad49b3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramEditPartProvider.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.provider;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.diagram.ui.services.editpart.AbstractEditPartProvider;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.BracketEdgeStyle;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.diagram.part.SiriusVisualIDRegistry;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.LostMessageEnd;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ObservationPoint;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentCompartmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.CombinedFragmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.EndOfLifeEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InstanceRoleEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.InteractionUseEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LostMessageEndEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ObservationPointEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.OperandCompartmentEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.OperandEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceBracketEdgeEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageNameEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.StateEditPart;
+
+/**
+ * Provides specific edit parts for Sirius Sequence Diagrams.
+ *
+ * @author pcdavid
+ */
+public class SequenceDiagramEditPartProvider extends AbstractEditPartProvider {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Class<?> getDiagramEditPartClass(View view) {
+ if (view instanceof Diagram) {
+ EObject semanticElement = ViewUtil.resolveSemanticElement(view);
+ if (semanticElement instanceof DDiagram && SequenceDiagram.viewpointElementPredicate().apply((DDiagram) semanticElement)) {
+ return SequenceDiagramEditPart.class;
+ }
+ }
+ return super.getDiagramEditPartClass(view);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // CHECKSTYLE:OFF
+ @Override
+ protected Class<?> getNodeEditPartClass(View view) {
+ if (view instanceof Node) {
+ EObject semanticElement = ViewUtil.resolveSemanticElement(view);
+ if (SiriusPackage.eINSTANCE.getDNode().isInstance(semanticElement)) {
+ if (InstanceRole.notationPredicate().apply(view)) {
+ return InstanceRoleEditPart.class;
+ } else if (Lifeline.notationPredicate().apply(view)) {
+ return LifelineEditPart.class;
+ } else if (Execution.notationPredicate().apply(view)) {
+ return ExecutionEditPart.class;
+ } else if (State.notationPredicate().apply(view)) {
+ return StateEditPart.class;
+ } else if (EndOfLife.notationPredicate().apply(view)) {
+ return EndOfLifeEditPart.class;
+ } else if (LostMessageEnd.notationPredicate().apply(view)) {
+ return LostMessageEndEditPart.class;
+ } else if (ObservationPoint.notationPredicate().apply(view)) {
+ return ObservationPointEditPart.class;
+ }
+ } else if (SiriusPackage.eINSTANCE.getDNodeContainer().isInstance(semanticElement)) {
+ if (InteractionUse.notationPredicate().apply(view)) {
+ return InteractionUseEditPart.class;
+ } else if (CombinedFragment.notationPredicate().apply(view)) {
+ return CombinedFragmentEditPart.class;
+ } else if (CombinedFragment.compartmentNotationPredicate().apply(view)) {
+ return CombinedFragmentCompartmentEditPart.class;
+ } else if (Operand.notationPredicate().apply(view)) {
+ return OperandEditPart.class;
+ } else if (Operand.compartmentNotationPredicate().apply(view)) {
+ return OperandCompartmentEditPart.class;
+ }
+ } else if (SiriusPackage.eINSTANCE.getDEdge().isInstance(semanticElement)) {
+ DEdge edge = (DEdge) semanticElement;
+ if (Message.viewpointElementPredicate().apply(edge) && SiriusVisualIDRegistry.getVisualID(view) == SequenceMessageNameEditPart.VISUAL_ID) {
+ return SequenceMessageNameEditPart.class;
+ }
+ }
+ }
+ return super.getNodeEditPartClass(view);
+ }
+
+ // CHECKSTYLE:ON
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Class<?> getEdgeEditPartClass(View view) {
+ Class<?> edgeEditPartClass = null;
+ if (view instanceof Edge) {
+ EObject semanticElement = ViewUtil.resolveSemanticElement(view);
+ if (semanticElement instanceof DEdge) {
+ DEdge edge = (DEdge) semanticElement;
+ if (Message.viewpointElementPredicate().apply((DEdge) semanticElement)) {
+ edgeEditPartClass = SequenceMessageEditPart.class;
+ } else if (SequenceDiagram.viewpointElementPredicate().apply(edge.getParentDiagram()) && edge.getStyle() instanceof BracketEdgeStyle) {
+ // Force the default location.
+ edgeEditPartClass = SequenceBracketEdgeEditPart.class;
+ }
+ }
+ }
+
+ if (edgeEditPartClass == null) {
+ edgeEditPartClass = super.getEdgeEditPartClass(view);
+ }
+
+ return edgeEditPartClass;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramLayoutProvider.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramLayoutProvider.java
new file mode 100644
index 0000000000..73831a1965
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/provider/SequenceDiagramLayoutProvider.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.provider;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.layout.SequenceLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+
+/**
+ * This provider contributes the appropriate layout provider for sequence
+ * diagrams.
+ *
+ * @author ymortier, mporhel
+ */
+public class SequenceDiagramLayoutProvider implements LayoutProvider {
+
+ /**
+ * The GMF layout provider.
+ */
+ private final AbstractLayoutEditPartProvider layoutProvider = new SequenceLayoutProvider();
+
+ /**
+ * {@inheritDoc}
+ */
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ return layoutProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean provides(final IGraphicalEditPart container) {
+ View notationView = container.getNotationView();
+ if (notationView != null) {
+ Diagram diagram = notationView.getDiagram();
+ return ISequenceElementAccessor.getSequenceDiagram(diagram).some();
+ }
+ return false;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/CreateRequestQuery.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/CreateRequestQuery.java
new file mode 100644
index 0000000000..6d58972eae
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/CreateRequestQuery.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.GraphicalHelper;
+
+/**
+ * Queries on GEF and GMF requests.
+ *
+ * @author pcdavid
+ */
+public class CreateRequestQuery extends RequestQuery {
+
+ private CreateRequest createRequest;
+
+ private SequenceDiagramEditPart sdep;
+
+ /**
+ * Constructor.
+ *
+ * @param request
+ * the request to query.
+ * @param sdep
+ * the diagram part to get zoom and scroll information.
+ */
+ public CreateRequestQuery(CreateRequest request, SequenceDiagramEditPart sdep) {
+ super(request);
+ this.createRequest = request;
+ this.sdep = sdep;
+ }
+
+ @Override
+ protected List<IGraphicalEditPart> getEditParts() {
+ return Collections.<IGraphicalEditPart> singletonList(sdep);
+ }
+
+ /**
+ * Get {@link Rectangle} image of the delta requested by the current
+ * {@link CreateRequest}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public Rectangle getLogicalDelta() {
+ Point location = createRequest.getLocation();
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ Dimension size = createRequest.getSize();
+ if (size == null) {
+ size = new Dimension(0, 0);
+ }
+ Rectangle result = new Rectangle(location, size);
+ if (sdep != null) {
+ GraphicalHelper.screen2logical(result, sdep);
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/DelegatingDiagramCommandFactory.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/DelegatingDiagramCommandFactory.java
new file mode 100644
index 0000000000..45e991d1a8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/DelegatingDiagramCommandFactory.java
@@ -0,0 +1,331 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DLabelled;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DRefreshable;
+import org.eclipse.sirius.DRepresentationElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.DragAndDropTarget;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.business.api.dialect.command.CreateRepresentationCommand;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.tool.BehaviorTool;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+import org.eclipse.sirius.description.tool.ContainerDropDescription;
+import org.eclipse.sirius.description.tool.DirectEditLabel;
+import org.eclipse.sirius.description.tool.DoubleClickDescription;
+import org.eclipse.sirius.description.tool.EdgeCreationDescription;
+import org.eclipse.sirius.description.tool.ExternalJavaAction;
+import org.eclipse.sirius.description.tool.NodeCreationDescription;
+import org.eclipse.sirius.description.tool.OperationAction;
+import org.eclipse.sirius.description.tool.PaneBasedSelectionWizardDescription;
+import org.eclipse.sirius.description.tool.PasteDescription;
+import org.eclipse.sirius.description.tool.ReconnectEdgeDescription;
+import org.eclipse.sirius.description.tool.RepresentationCreationDescription;
+import org.eclipse.sirius.description.tool.SelectionWizardDescription;
+import org.eclipse.sirius.description.tool.ToolDescription;
+import org.eclipse.sirius.description.validation.ValidationFix;
+import org.eclipse.sirius.tools.api.command.DCommand;
+import org.eclipse.sirius.tools.api.command.IDiagramCommandFactory;
+import org.eclipse.sirius.tools.api.command.ui.UICallBack;
+import org.eclipse.sirius.tools.api.ui.IExternalJavaAction;
+
+/**
+ * An implementation of <code>IDiagramCommandFactory</code> which delegates to
+ * another one. Useful to customize only some of the methods when one does not
+ * control the instantiation of the factory to customize.
+ *
+ * @author pcdavid
+ */
+@SuppressWarnings("deprecation")
+public class DelegatingDiagramCommandFactory implements IDiagramCommandFactory {
+ private final IDiagramCommandFactory baseFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param baseFactory
+ * the factory to delegate to.
+ */
+ public DelegatingDiagramCommandFactory(IDiagramCommandFactory baseFactory) {
+ this.baseFactory = Preconditions.checkNotNull(baseFactory);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildCreateNodeCommandFromTool(DNode node, NodeCreationDescription tool) {
+ return baseFactory.buildCreateNodeCommandFromTool(node, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildCreateContainerCommandFromTool(DDiagram diagram, ContainerCreationDescription tool) {
+ return baseFactory.buildCreateContainerCommandFromTool(diagram, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildCreateContainerCommandFromTool(DDiagramElementContainer nodeContainer, ContainerCreationDescription tool) {
+ return baseFactory.buildCreateContainerCommandFromTool(nodeContainer, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public DCommand buildCreateDiagramFromDescription(DiagramDescription description, EObject semanticElement) {
+ return baseFactory.buildCreateDiagramFromDescription(description, semanticElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public DCommand buildCreateDiagramFromDescription(DiagramDescription description, EObject semanticElement, IProgressMonitor monitor) {
+ return baseFactory.buildCreateDiagramFromDescription(description, semanticElement, monitor);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildCreateEdgeCommandFromTool(EdgeTarget source, EdgeTarget target, EdgeCreationDescription tool) {
+ return baseFactory.buildCreateEdgeCommandFromTool(source, target, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildCreateNodeCommandFromTool(DDiagram diagram, NodeCreationDescription tool) {
+ return baseFactory.buildCreateNodeCommandFromTool(diagram, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildCreateNodeCommandFromTool(DDiagramElementContainer container, NodeCreationDescription tool) {
+ return baseFactory.buildCreateNodeCommandFromTool(container, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CreateRepresentationCommand buildCreateRepresentationFromDescription(RepresentationCreationDescription desc, DRepresentationElement element, String newRepresentationName) {
+ return baseFactory.buildCreateRepresentationFromDescription(desc, element, newRepresentationName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDeleteDiagram(DDiagram vp) {
+ return baseFactory.buildDeleteDiagram(vp);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDeleteDiagramElement(DDiagramElement element) {
+ return baseFactory.buildDeleteDiagramElement(element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDeleteFromDiagramCommand(DDiagramElement element) {
+ return baseFactory.buildDeleteFromDiagramCommand(element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDirectEditLabelFromTool(DLabelled labelled, DirectEditLabel directEditTool, String newValue) {
+ return baseFactory.buildDirectEditLabelFromTool(labelled, directEditTool, newValue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDoExecuteDetailsOperation(DSemanticDecorator target, RepresentationCreationDescription desc, String newRepresentationName) {
+ return baseFactory.buildDoExecuteDetailsOperation(target, desc, newRepresentationName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDoubleClickOnElementCommandFromTool(DDiagramElement dDiagramElement, DoubleClickDescription tool) {
+ return baseFactory.buildDoubleClickOnElementCommandFromTool(dDiagramElement, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDropInContainerCommandFromTool(DragAndDropTarget dContainer, DDiagramElement element, ContainerDropDescription tool) {
+ return baseFactory.buildDropInContainerCommandFromTool(dContainer, element, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildDropInContainerCommandFromTool(DragAndDropTarget dContainer, EObject droppedElement, ContainerDropDescription tool) {
+ return baseFactory.buildDropInContainerCommandFromTool(dContainer, droppedElement, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildGenericToolCommandFromTool(EObject containerView, ToolDescription toolDesc) {
+ return baseFactory.buildGenericToolCommandFromTool(containerView, toolDesc);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildHideCommand(Set<EObject> elementsToHide) {
+ return baseFactory.buildHideCommand(elementsToHide);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ */
+ public Command buildHideLabelCommand(Set<EObject> elementsToHide) {
+ return baseFactory.buildHideLabelCommand(elementsToHide);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildJavaActionFromTool(ExternalJavaAction tool, Collection<DSemanticDecorator> selectedViews, IExternalJavaAction javaAction) {
+ return baseFactory.buildJavaActionFromTool(tool, selectedViews, javaAction);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildLaunchRuleCommandFromTool(DSemanticDecorator rootObject, BehaviorTool tool, boolean executeFromRootContainer, boolean deepProcess) {
+ return baseFactory.buildLaunchRuleCommandFromTool(rootObject, tool, executeFromRootContainer, deepProcess);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildOperationActionFromTool(OperationAction tool, Collection<DSemanticDecorator> selectedViews) {
+ return baseFactory.buildOperationActionFromTool(tool, selectedViews);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildPaneBasedSelectionWizardCommandFromTool(PaneBasedSelectionWizardDescription tool, DSemanticDecorator dContainer,
+ Collection<EObject> selectedElement) {
+ return baseFactory.buildPaneBasedSelectionWizardCommandFromTool(tool, dContainer, selectedElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildQuickFixOperation(ValidationFix fix, EObject fixTarget, DDiagram diagram) {
+ return baseFactory.buildQuickFixOperation(fix, fixTarget, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildReconnectEdgeCommandFromTool(ReconnectEdgeDescription tool, DEdge edge, EdgeTarget source, EdgeTarget target) {
+ return baseFactory.buildReconnectEdgeCommandFromTool(tool, edge, source, target);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildRefreshCommand(DRefreshable refreshableElement) {
+ return baseFactory.buildRefreshCommand(refreshableElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildRevealCommand(DDiagramElement diagramElement) {
+ return baseFactory.buildRevealCommand(diagramElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildRevealElementsCommand(DDiagram diagram) {
+ return baseFactory.buildRevealElementsCommand(diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Command buildRevealLabelCommand(DDiagramElement diagramElement) {
+ return baseFactory.buildRevealLabelCommand(diagramElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildRevealElementsCommand(Set<DDiagramElement> elementsToReveal) {
+ return baseFactory.buildRevealElementsCommand(elementsToReveal);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public org.eclipse.emf.common.command.Command buildSelectionWizardCommandFromTool(SelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement) {
+ return baseFactory.buildSelectionWizardCommandFromTool(tool, dContainer, selectedElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAutoRefreshDView(boolean autoRefreshDView) {
+ baseFactory.setAutoRefreshDView(autoRefreshDView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setUserInterfaceCallBack(UICallBack newCB) {
+ baseFactory.setUserInterfaceCallBack(newCB);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Command buildPasteCommandFromTool(DSemanticDecorator dContainer, DSemanticDecorator element, PasteDescription tool) {
+ return baseFactory.buildPasteCommandFromTool(dContainer, element, tool);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Command buildPasteCommandFromTool(DSemanticDecorator dContainer, EObject droppedElement, PasteDescription tool) {
+ return baseFactory.buildPasteCommandFromTool(dContainer, droppedElement, tool);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsHelper.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsHelper.java
new file mode 100644
index 0000000000..71e3a3dca2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsHelper.java
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ISequenceEventEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceMessageEditPart;
+import org.eclipse.sirius.diagram.ui.tools.internal.util.EditPartQuery;
+
+/**
+ * Helper class with utilities to deal with GMF edit parts.
+ *
+ * @author pcdavid
+ */
+public final class EditPartsHelper {
+
+ /**
+ * A predicate which checks that a given edit part is active.
+ *
+ * @author pcdavid
+ */
+ private static enum IsValidPredicate implements Predicate<IGraphicalEditPart> {
+ INSTANCE;
+
+ public boolean apply(IGraphicalEditPart input) {
+ return input.getParent() != null;
+ }
+ }
+
+ private EditPartsHelper() {
+ // Prevents instantiation.
+ }
+
+ /**
+ * Returns a predicate which checks that a given edit part is active.
+ *
+ * @return a predicate which checks that a given edit part is active.
+ */
+ public static Predicate<IGraphicalEditPart> isValid() {
+ return IsValidPredicate.INSTANCE;
+ }
+
+ /**
+ * Finds all the sequence messages whose source or target is the specified
+ * element or any of its descendant edit parts, without duplicates.
+ *
+ * @param element
+ * the element from which to start the search for messages.
+ * @return the messages found without duplicates.
+ * @deprecated
+ */
+ @Deprecated
+ public static Set<SequenceMessageEditPart> getAllMessages(IGraphicalEditPart element) {
+ Set<SequenceMessageEditPart> allMessages = Sets.newHashSet();
+ allMessages.addAll(EditPartsHelper.getAllMessagesFrom(element));
+ allMessages.addAll(EditPartsHelper.getAllMessagesTo(element));
+ return allMessages;
+ }
+
+ /**
+ * Finds all the sequence messages whose source is the specified element or
+ * any of its descendant edit parts.
+ *
+ * @param element
+ * the element from which to start the search for messages.
+ * @return the messages found.
+ * @deprecated
+ */
+ @Deprecated
+ public static List<SequenceMessageEditPart> getAllMessagesFrom(IGraphicalEditPart element) {
+ List<SequenceMessageEditPart> messagesParts = Lists.newArrayList();
+ EditPartsHelper.addAllMessagesFrom(element, messagesParts);
+ return messagesParts;
+ }
+
+ /**
+ * Finds all the sequence messages whose target is the specified element or
+ * any of its descendant edit parts.
+ *
+ * @param element
+ * the element from which to start the search for messages.
+ * @return the messages found.
+ * @deprecated
+ */
+ @Deprecated
+ private static List<SequenceMessageEditPart> getAllMessagesTo(IGraphicalEditPart element) {
+ List<SequenceMessageEditPart> messagesParts = Lists.newArrayList();
+ EditPartsHelper.addAllMessagesTo(element, messagesParts);
+ return messagesParts;
+ }
+
+ /**
+ * Finds all the (non root) executions contained inside the specified
+ * element or any of its descendant edit parts.
+ *
+ * @param element
+ * the element from which to start the search for executions.
+ * @return the executions found.
+ * @deprecated
+ */
+ @Deprecated
+ public static List<ExecutionEditPart> getAllExecutions(IGraphicalEditPart element) {
+ return Lists.newArrayList(Iterators.filter(Iterators.filter(new EditPartsTreeIterator(element), ExecutionEditPart.class), EditPartsHelper.isValid()));
+ }
+
+ /**
+ * Finds all the lifelines contained inside the specified element or any of
+ * its descendant edit parts.
+ *
+ * @param element
+ * the element from which to start the search for executions.
+ * @return the executions found.
+ *
+ * @deprecated
+ */
+ @Deprecated
+ public static List<LifelineEditPart> getAllLifelines(IGraphicalEditPart element) {
+ return Lists.newArrayList(Iterators.filter(Iterators.filter(new EditPartsTreeIterator(element), LifelineEditPart.class), EditPartsHelper.isValid()));
+ }
+
+ /**
+ * Finds all the sequence messages whose source is the specified element or
+ * any of its descendant edit parts and add them to a collection.
+ *
+ * @param element
+ * the element from which to start the search for messages.
+ * @param messages
+ * the collection in which to add the messages.
+ */
+ private static void addAllMessagesFrom(IGraphicalEditPart element, Collection<SequenceMessageEditPart> messages) {
+ for (IGraphicalEditPart connectionPart : Iterables.filter(element.getSourceConnections(), IGraphicalEditPart.class)) {
+ if (connectionPart instanceof SequenceMessageEditPart && EditPartsHelper.isValid().apply(connectionPart)) {
+ messages.add((SequenceMessageEditPart) connectionPart);
+ }
+ }
+ if (element instanceof SequenceMessageEditPart && EditPartsHelper.isValid().apply(element)) {
+ messages.add((SequenceMessageEditPart) element);
+ }
+ for (IGraphicalEditPart child : Iterables.filter(element.getChildren(), IGraphicalEditPart.class)) {
+ EditPartsHelper.addAllMessagesFrom(child, messages);
+ }
+ }
+
+ /**
+ * Finds all the sequence messages whose target is the specified element or
+ * any of its descendant edit parts and add them to a collection.
+ *
+ * @param element
+ * the element from which to start the search for messages.
+ * @param messages
+ * the collection in which to add the messages.
+ */
+ private static void addAllMessagesTo(IGraphicalEditPart element, Collection<SequenceMessageEditPart> messages) {
+ for (IGraphicalEditPart connectionPart : Iterables.filter(element.getTargetConnections(), IGraphicalEditPart.class)) {
+ if (connectionPart instanceof SequenceMessageEditPart && EditPartsHelper.isValid().apply(connectionPart)) {
+ messages.add((SequenceMessageEditPart) connectionPart);
+ }
+ }
+ if (element instanceof SequenceMessageEditPart && EditPartsHelper.isValid().apply(element)) {
+ messages.add((SequenceMessageEditPart) element);
+ }
+ for (IGraphicalEditPart child : Iterables.filter(element.getChildren(), IGraphicalEditPart.class)) {
+ EditPartsHelper.addAllMessagesTo(child, messages);
+ }
+ }
+
+ /**
+ * Finds all the events in the specified diagram which have a specific
+ * semantic target.
+ *
+ * @param diagram
+ * the sequence diagram.
+ * @param semanticElement
+ * the semantic element.
+ * @return all the events in the diagram which have the specified semantic
+ * element as target.
+ */
+ public static Collection<ISequenceEventEditPart> getEventsForSemanticElement(SequenceDiagramEditPart diagram, EObject semanticElement) {
+ ECrossReferenceAdapter xref = EditPartsHelper.getCrossReferencer(semanticElement);
+ if (xref == null) {
+ return Collections.emptySet();
+ } else {
+ Map<?, ?> registry = diagram.getViewer().getEditPartRegistry();
+ Collection<ISequenceEventEditPart> result = Lists.newArrayList();
+ for (Setting setting : xref.getInverseReferences(semanticElement)) {
+ if (EditPartsHelper.isDiagramElementTargetReference(setting)) {
+ DDiagramElement dde = (DDiagramElement) setting.getEObject();
+ Object registered = registry.get(dde);
+ if (registered instanceof ISequenceEventEditPart && EditPartsHelper.isValid().apply((ISequenceEventEditPart) registered)) {
+ result.add((ISequenceEventEditPart) registry.get(dde));
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ private static boolean isDiagramElementTargetReference(Setting setting) {
+ EReference targetReference = SiriusPackage.eINSTANCE.getDSemanticDecorator_Target();
+ return setting.getEObject() instanceof DDiagramElement && setting.getEStructuralFeature().equals(targetReference);
+ }
+
+ private static ECrossReferenceAdapter getCrossReferencer(EObject semanticElement) {
+ Session session = SessionManager.INSTANCE.getSession(semanticElement);
+ if (session != null) {
+ return session.getSemanticCrossReferencer();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds the parent {@link LifelineEditPart}.
+ *
+ * @param part
+ * the {@link IGraphicalEditPart} to find its parent
+ * {@link LifelineEditPart}.
+ * @return the parent {@link LifelineEditPart}
+ */
+ public static LifelineEditPart findParentLifeline(IGraphicalEditPart part) {
+ final LifelineEditPart result;
+ if (part instanceof LifelineEditPart && EditPartsHelper.isValid().apply(part)) {
+ result = (LifelineEditPart) part;
+ } else if (part != null) {
+ result = new EditPartQuery(part).getFirstAncestorOfType(LifelineEditPart.class);
+ } else {
+ result = null;
+ }
+ return result;
+ }
+
+ /**
+ * Finds and returns the ISequenceEvent corresponding to the given
+ * SingleEventEnd.
+ *
+ * @param end
+ * the end to look for
+ * @param sdep
+ * the SequenceDiagramEditPart to inspect
+ * @return the ISequenceEvent corresponding to the given part
+ */
+ public static ISequenceEventEditPart findISequenceEvent(SingleEventEnd end, SequenceDiagramEditPart sdep) {
+ for (ISequenceEventEditPart ise : Iterables.concat(EditPartsHelper.getAllExecutions(sdep), EditPartsHelper.getAllMessagesFrom(sdep))) {
+ EObject semanticEvent = ise.resolveTargetSemanticElement();
+ if (end.getSemanticEvent().equals(semanticEvent)) {
+ return ise;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the sequence diagram edit part owning the edit part.
+ *
+ * @param editPart
+ * the edit part.
+ * @return the sequence diagram edit part owning the part.
+ */
+ public static SequenceDiagramEditPart getSequenceDiagramPart(IGraphicalEditPart editPart) {
+ if (editPart instanceof SequenceDiagramEditPart) {
+ return (SequenceDiagramEditPart) editPart;
+ }
+ IGraphicalEditPart current = editPart;
+ if (editPart instanceof ConnectionEditPart) {
+ ConnectionEditPart conn = (ConnectionEditPart) editPart;
+ current = (IGraphicalEditPart) conn.getSource();
+ }
+ return new EditPartQuery(current).getFirstAncestorOfType(SequenceDiagramEditPart.class);
+ }
+
+ /**
+ * Get a {@link SequenceDiagram} from a EditPart of Sequence representation.
+ *
+ * @param host
+ * editPart of Sequence representation
+ * @param <T>
+ * any subtype of EditPart
+ * @return the {@link SequenceDiagram} of a sequence representation
+ */
+ public static <T extends EditPart> SequenceDiagram getSequenceDiagram(T host) {
+ EditPart parent = host;
+ while (parent != null && !(parent instanceof ISequenceEventEditPart || parent instanceof SequenceDiagramEditPart)) {
+ parent = parent.getParent();
+ }
+ SequenceDiagram sequenceDiagram = null;
+ if (parent instanceof SequenceDiagramEditPart) {
+ sequenceDiagram = ((SequenceDiagramEditPart) parent).getSequenceDiagram();
+ } else if (parent instanceof ISequenceEventEditPart) {
+ sequenceDiagram = ((ISequenceEventEditPart) parent).getISequenceEvent().getDiagram();
+ }
+ return sequenceDiagram;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsTreeIterator.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsTreeIterator.java
new file mode 100644
index 0000000000..3a0c432f51
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/EditPartsTreeIterator.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.common.util.AbstractTreeIterator;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+
+/**
+ * A tree iterator to iterate on hierarchies of GMF edit parts.
+ *
+ * @author pcdavid
+ */
+class EditPartsTreeIterator extends AbstractTreeIterator<IGraphicalEditPart> {
+ /**
+ * Generated serial version UID.
+ */
+ private static final long serialVersionUID = 3234398995856675133L;
+
+ /**
+ * Creates a new tree iterator on the specified edit part and all its
+ * descendant edit parts.
+ *
+ * @param root
+ * the root edit part of the iteration.
+ */
+ public EditPartsTreeIterator(IGraphicalEditPart root) {
+ super(root);
+ }
+
+ /**
+ * Creates a new tree iterator on the descendants of the specified edit
+ * part.
+ *
+ * @param root
+ * the root edit part of the iteration.
+ * @param includeRoot
+ * if <code>true</code>, the iterator includes the root element.
+ */
+ public EditPartsTreeIterator(IGraphicalEditPart root, boolean includeRoot) {
+ super(root, includeRoot);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Iterator<? extends IGraphicalEditPart> getChildren(Object object) {
+ if (object instanceof IGraphicalEditPart) {
+ Iterable<IGraphicalEditPart> children = Iterables.filter(((IGraphicalEditPart) object).getChildren(), IGraphicalEditPart.class);
+ return children.iterator();
+ } else {
+ return Iterators.emptyIterator();
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/FinalParentHelper.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/FinalParentHelper.java
new file mode 100644
index 0000000000..9be87a22d5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/FinalParentHelper.java
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+public class FinalParentHelper {
+ private final AbstractNodeEvent self;
+
+ private final RequestQuery request;
+
+ private Range expansionZone;
+
+ private ISequenceEvent globalFinalParent;
+
+ /**
+ * Constructor.
+ *
+ * @param self
+ * the execution which will be resized.
+ * @param resizeRequest
+ * the resize query.
+ */
+ public FinalParentHelper(AbstractNodeEvent self, RequestQuery resizeRequest) {
+ this.self = Preconditions.checkNotNull(self);
+ this.request = Preconditions.checkNotNull(resizeRequest);
+ Preconditions.checkArgument(resizeRequest.isResize());
+ }
+
+ /**
+ * Determines what event will be the direct parent of this execution after
+ * the execution of the specified request. Returns <code>null</code> if the
+ * request is invalid. Calling this method also sets the
+ * <code>expansionZone</code> field: it is set to <code>null</code> if the
+ * returned parent can accept this execution directly, or to the vertical
+ * range which needs to be expanded on the future parent if there is not yet
+ * enough room to contain this execution.
+ */
+ public void computeFinalParent() {
+ Range fullFinalRange = getFullFinalRange();
+ if (fullFinalRange != null) {
+ if (isInvalidInteractionInsideOperand(fullFinalRange)) {
+ globalFinalParent = null;
+ } else if (fullFinalRange != null && request.isResize()) {
+ globalFinalParent = getFinalParentOnResize(fullFinalRange);
+ }
+ }
+ }
+
+ /**
+ * Validates if the execution resize is valid if located in an operand.
+ *
+ * @param fullFinalRange
+ * the new range of the resized {@link ISequenceEvent}
+ * @return if the execution resize is valid if located in an operand.
+ */
+ private boolean isInvalidInteractionInsideOperand(Range fullFinalRange) {
+ boolean result = false;
+ Option<Operand> parentOperand = self.getParentOperand();
+ if (request.isResize()) {
+ result = parentOperand.some() && !parentOperand.get().getVerticalRange().includes(fullFinalRange);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the computed final parent of the execution after the resize.
+ *
+ * @return the final parent of the execution after the resize.
+ */
+ public ISequenceEvent getFinalParent() {
+ return globalFinalParent;
+ }
+
+ /**
+ * Returns the auto-expansion required before the resize.
+ *
+ * @return the auto-expansion required before the resize.
+ */
+ public Range getRequiredExpansion() {
+ return expansionZone;
+ }
+
+ /**
+ * Computes the full final range which would be occupied by this execution
+ * and any of the elements resized along with it if we accept the specified
+ * request.
+ *
+ * @param request
+ * the request for changing the size/location of this execution
+ * @return the final vertical range of the execution and its linked messages
+ * (if any) if we accept the request.
+ */
+ private Range getFullFinalRange() {
+ Rectangle newBounds = request.getLogicalTransformedRectangle(self.getProperLogicalBounds());
+ if (newBounds.width < 0 || newBounds.height < 0) {
+ return null;
+ }
+ Range fullFinalRange = Range.verticalRange(newBounds);
+
+ if (self instanceof Execution) {
+ Execution execution = (Execution) self;
+
+ Option<Message> startMessage = execution.getStartMessage();
+ if (startMessage.some() && !startMessage.get().surroundsEventOnSameLifeline()) {
+ int startY = fullFinalRange.getLowerBound() - startMessage.get().getVerticalRange().width();
+ fullFinalRange = new Range(startY, fullFinalRange.getUpperBound());
+ }
+ Option<Message> endMessage = execution.getEndMessage();
+ if (endMessage.some() && !endMessage.get().surroundsEventOnSameLifeline()) {
+ int finishY = fullFinalRange.getUpperBound() + endMessage.get().getVerticalRange().width();
+ fullFinalRange = new Range(fullFinalRange.getLowerBound(), finishY);
+ }
+ }
+
+ return fullFinalRange;
+ }
+
+ private ISequenceEvent getFinalParentOnResize(final Range fullFinalRange) {
+ Preconditions.checkArgument(request.isResize());
+ final Collection<ISequenceEvent> remoteErrors = Sets.newHashSet();
+
+ /*
+ * A simple resizing can not change the parent of an execution.
+ */
+ ISequenceEvent finalParent = self.getParentEvent();
+ /*
+ * We must still check that the resizing is valid, in that it will not
+ * cause an overlap/conflict with sibling events.
+ */
+ final Collection<ISequenceEvent> linkedSiblings = FinalParentHelper.computeLinkedSiblings(request);
+ Iterable<ISequenceEvent> finalSiblings = EventEndHelper.getIndependantEvents(self, finalParent.getSubEvents());
+
+ final Option<Lifeline> selfLifeline = self.getLifeline();
+ Predicate<ISequenceEvent> sameLifeline = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ Option<Lifeline> inputLifeline = input.getLifeline();
+ boolean same = !inputLifeline.some() || (selfLifeline.some() && inputLifeline.get() == selfLifeline.get());
+
+ if (input instanceof Message) {
+ Option<Lifeline> sourceLifeline = ((Message) input).getSourceLifeline();
+ same = same || !sourceLifeline.some() || (selfLifeline.some() && sourceLifeline.get() == selfLifeline.get());
+ Option<Lifeline> tgtLifeline = ((Message) input).getTargetLifeline();
+ same = same || !tgtLifeline.some() || (selfLifeline.some() && tgtLifeline.get() == selfLifeline.get());
+ }
+
+ return same;
+ }
+ };
+
+ Predicate<ISequenceEvent> intersectsFinalBounds = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ Range inputRange = input.getVerticalRange();
+ boolean intersection = inputRange.intersects(fullFinalRange) && !linkedSiblings.contains(input);
+ // Some event could not be parents : states for examples.
+ boolean includedInput = !self.getValidSubEventsRange().isEmpty() && fullFinalRange.includes(inputRange.grown(1));
+
+ if (input instanceof Message) {
+ Message msg = (Message) input;
+
+ if (msg.isReflective() && !includedInput) {
+ intersection = inputRange.intersects(fullFinalRange) && !inputRange.includes(fullFinalRange);
+ includedInput = inputRange.includes(fullFinalRange);
+ }
+
+ if (intersection && msg.isCompoundMessage()) {
+ Iterable<Execution> compoundEvents = Iterables.filter(EventEndHelper.getCompoundEvents(input), Execution.class);
+ if (!Iterables.isEmpty(compoundEvents)) {
+ Execution remoteExec = compoundEvents.iterator().next();
+ if (remoteExec != null && remoteExec.getEndMessage().some() && !fullFinalRange.includes(remoteExec.getExtendedVerticalRange())) {
+ includedInput = false;
+ remoteErrors.add(remoteExec);
+ }
+ }
+ }
+ }
+ return intersection && !includedInput;
+ }
+ };
+
+ /*
+ * Removes parent combined fragment to be able to resize an execution in
+ * a combined fragment
+ */
+ Predicate<ISequenceEvent> notParentCombinedFragment = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ if (input instanceof CombinedFragment && self.getLifeline().some()) {
+ CombinedFragment combinedFragment = (CombinedFragment) input;
+ return !(combinedFragment.computeCoveredLifelines().contains(self.getLifeline().get()) && combinedFragment.getVerticalRange().includes(fullFinalRange));
+ }
+ return true;
+ }
+ };
+
+ Iterable<ISequenceEvent> invalids = Iterables.filter(finalSiblings, Predicates.and(sameLifeline, notParentCombinedFragment, intersectsFinalBounds));
+ if (!Iterables.isEmpty(invalids)) {
+ finalParent = null;
+ for (ISequenceEvent ise : Iterables.concat(invalids, remoteErrors)) {
+ Range verticalRange = ise.getVerticalRange();
+
+ if (ise instanceof Message && ((Message) ise).isReflective() && verticalRange.includes(self.getVerticalRange())) {
+ verticalRange = new Range(verticalRange.getUpperBound(), verticalRange.getUpperBound());
+ }
+
+ if (request.isResizeFromBottom()) {
+ Range errorRange = new Range(verticalRange.getLowerBound() - 1, Math.max(verticalRange.getLowerBound(), fullFinalRange.getUpperBound()));
+ expansionZone = expansionZone == null ? errorRange : errorRange.union(expansionZone);
+ }
+ }
+ }
+ return finalParent;
+ }
+
+ /**
+ * Get list of {@link ISequenceEvent} from the request.
+ *
+ * @param request
+ * request of resize
+ *
+ * @return list of {@link ISequenceEvent}
+ */
+ public static ArrayList<ISequenceEvent> computeLinkedSiblings(RequestQuery request) {
+ final ArrayList<ISequenceEvent> linkedSiblings = Lists.newArrayList();
+ Set<Execution> parts = request.getExecutions();
+ for (Execution execution : parts) {
+ linkedSiblings.add(execution);
+ linkedSiblings.addAll(execution.findLinkedExecutions(true));
+ linkedSiblings.addAll(new ISequenceEventQuery(execution).getAllDescendants());
+ }
+ return linkedSiblings;
+ }
+
+ /**
+ * Get the {@link ISequenceEvent} for ...
+ *
+ * @param self
+ * {@link AbstractNodeEvent} to consider.
+ * @param smep
+ * the {@link Message} to consider.
+ * @param deltaY
+ * the deltaY to use
+ * @param deltaHeight
+ * the deltaHeight to use
+ *
+ * @return the {@link ISequenceEvent} for ...
+ */
+ public static ISequenceEvent getFinalRemoteParent(AbstractNodeEvent self, Message smep, int deltaY, int deltaHeight) {
+ Range finalMessageRange = smep.getVerticalRange().shifted(deltaY);
+ if (deltaHeight != 0) {
+ finalMessageRange = new Range(finalMessageRange.getLowerBound(), finalMessageRange.getUpperBound() + deltaHeight);
+ }
+ Set<ISequenceEvent> allMovedElements = new ISequenceEventQuery(self).getAllDescendants();
+ allMovedElements.add(self);
+
+ ISequenceEvent sourceParent = (smep.getSourceElement() instanceof ISequenceEvent) ? (ISequenceEvent) smep.getSourceElement() : null;
+
+ /*
+ * The target will not be an ISequenceEvent for creation and destruction
+ * messages as instance roles and EOL are not ISequenceEvents.
+ */
+ ISequenceEvent targetParent = (smep.getTargetElement() instanceof ISequenceEvent) ? (ISequenceEvent) smep.getTargetElement() : null;
+ ISequenceEvent remoteParent = allMovedElements.contains(sourceParent) ? targetParent : sourceParent;
+
+ ISequenceEvent finalRemoteParent = null;
+ if (remoteParent != null) {
+ Option<Lifeline> remoteLifeline = remoteParent.getLifeline();
+ if (remoteLifeline.some()) {
+ EventFinder remoteFinder = new EventFinder(remoteLifeline.get());
+ remoteFinder.setEventsToIgnore(Predicates.in(Lists.newArrayList(allMovedElements)));
+ finalRemoteParent = remoteFinder.findMostSpecificEvent(finalMessageRange);
+ }
+ }
+ return finalRemoteParent;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/RequestQuery.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/RequestQuery.java
new file mode 100644
index 0000000000..f1c50f4e11
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/RequestQuery.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gef.requests.CreateRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Execution;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.description.BasicMessageMapping;
+import org.eclipse.sirius.diagram.sequence.description.CreationMessageMapping;
+import org.eclipse.sirius.diagram.sequence.description.DestructionMessageMapping;
+import org.eclipse.sirius.diagram.sequence.description.tool.MessageCreationTool;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.ExecutionEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.policy.SequenceMessageEditPolicy;
+
+/**
+ * Queries on GEF and GMF requests.
+ *
+ * @author pcdavid
+ */
+public class RequestQuery extends org.eclipse.sirius.diagram.business.internal.query.RequestQuery {
+
+ /**
+ * Constaint to check if request if from another indirect request.
+ */
+ public static final String IS_MOVED_BY_PARENT_EXECUTION = "isMovedByParentExecution";
+
+ /**
+ * Constructor.
+ *
+ * @param request
+ * the request to query.
+ */
+ public RequestQuery(Request request) {
+ super(request);
+ }
+
+ /**
+ * Determines the final bounds for this execution (in logical coordinates)
+ * if we accept the specified request. Uses Draw2D information to get the
+ * current bounds.
+ *
+ * @param self
+ * {@link AbstractNodeEvent} in move/resize
+ *
+ * @return final bounds of self
+ */
+ public Rectangle getFinalBounds(ExecutionEditPart self) {
+ Rectangle bounds = self.getFigure().getBounds().getCopy();
+ return getLogicalTransformedRectangle(bounds);
+ }
+
+ /**
+ * Get the list of AbstractNodeEvents from the current GroupRequest.
+ *
+ * @return the list of AbstractNodeEvents
+ */
+ public Set<AbstractNodeEvent> getAbstractNodeEvent() {
+ List<IGraphicalEditPart> editParts = getEditParts();
+
+ if (editParts.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ Set<AbstractNodeEvent> result = Sets.newHashSet();
+ for (IGraphicalEditPart part : editParts) {
+ Option<AbstractNodeEvent> execution = ISequenceElementAccessor.getAbstractNodeEvent(part.getNotationView());
+ if (execution.some()) {
+ result.add(execution.get());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the list of Executions from the current GroupRequest.
+ *
+ * @return the list of Executions
+ */
+ public Set<Execution> getExecutions() {
+ List<IGraphicalEditPart> editParts = getEditParts();
+
+ if (editParts.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ Set<Execution> result = Sets.newHashSet();
+ for (IGraphicalEditPart part : editParts) {
+ Option<Execution> execution = ISequenceElementAccessor.getExecution(part.getNotationView());
+ if (execution.some()) {
+ result.add(execution.get());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the list of {@link ISequenceEvent} from the current GroupRequest.
+ *
+ * @return the list of Executions
+ */
+ public Set<ISequenceEvent> getISequenceEvents() {
+ List<IGraphicalEditPart> editParts = getEditParts();
+
+ if (editParts.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ Set<ISequenceEvent> result = Sets.newHashSet();
+ for (IGraphicalEditPart part : editParts) {
+ Option<ISequenceEvent> ise = ISequenceElementAccessor.getISequenceEvent(part.getNotationView());
+ if (ise.some()) {
+ result.add(ise.get());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the list of InstanceRoles from the current GroupRequest.
+ *
+ * @return the list of InstanceRoles
+ */
+ public List<InstanceRole> getInstanceRoles() {
+ List<IGraphicalEditPart> editParts = getEditParts();
+
+ if (editParts.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<InstanceRole> instanceRoles = new ArrayList<InstanceRole>();
+ for (IGraphicalEditPart part : editParts) {
+ Option<InstanceRole> instanceRole = ISequenceElementAccessor.getInstanceRole(part.getNotationView());
+ if (instanceRole.some()) {
+ instanceRoles.add(instanceRole.get());
+ }
+ }
+ return instanceRoles;
+ }
+
+ /**
+ * Tests whether this execution is being moved indirectly by ancestor, or
+ * because is linked to a moving execution, as part of the request, in which
+ * case the parent/main execution is responsible for most of the work.
+ *
+ * @return true if this request if from another indirect request
+ */
+ public boolean isExecutionMovedIndirectly() {
+ Map<?, ?> extData = request.getExtendedData();
+ if (request instanceof ChangeBoundsRequest && extData != null && extData.get(IS_MOVED_BY_PARENT_EXECUTION) instanceof Boolean) {
+ Boolean value = (Boolean) extData.get(IS_MOVED_BY_PARENT_EXECUTION);
+ return value.booleanValue();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the current request is a creation request for a new create
+ * message.
+ *
+ * @return true if the current request is a creation request for a new
+ * create message
+ */
+ public boolean isCreateMessageCreation() {
+ boolean result = false;
+ if (!isNoteAttachmentCreationRequest() && request instanceof CreateRequest) {
+ CreateRequest createRequest = (CreateRequest) request;
+ if (createRequest.getNewObject() instanceof MessageCreationTool) {
+ MessageCreationTool messageCreationTool = (MessageCreationTool) createRequest.getNewObject();
+ result = Iterables.any(messageCreationTool.getEdgeMappings(), Predicates.instanceOf(CreationMessageMapping.class));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if the current request is a creation request for a new destroy
+ * message.
+ *
+ * @return true if the current request is a creation request for a new
+ * destroy message
+ */
+ public boolean isDestroyMessageCreation() {
+ boolean result = false;
+ if (!isNoteAttachmentCreationRequest() && request instanceof CreateRequest) {
+ CreateRequest createRequest = (CreateRequest) request;
+ if (createRequest.getNewObject() instanceof MessageCreationTool) {
+ MessageCreationTool messageCreationTool = (MessageCreationTool) createRequest.getNewObject();
+ result = Iterables.any(messageCreationTool.getEdgeMappings(), Predicates.instanceOf(DestructionMessageMapping.class));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if the current request is a creation request for a new standard
+ * message.
+ *
+ * @return true if the current request is a creation request for a new
+ * standard message
+ */
+ public boolean isStandardMessageCreation() {
+ boolean result = false;
+ if (!isNoteAttachmentCreationRequest() && request instanceof CreateRequest) {
+ CreateRequest createRequest = (CreateRequest) request;
+ if (createRequest.getNewObject() instanceof MessageCreationTool) {
+ MessageCreationTool messageCreationTool = (MessageCreationTool) createRequest.getNewObject();
+ result = Iterables.any(messageCreationTool.getEdgeMappings(), Predicates.instanceOf(BasicMessageMapping.class));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Request created from SequenceMessageEditPolicy.
+ *
+ * @return true if created from message;
+ */
+ public boolean isDirectedByMessage() {
+ Object object = request.getExtendedData().get(SequenceMessageEditPolicy.REQUEST_FROM_SEQUENCE_MESSAGE_EDIT_POLICY);
+ return object instanceof Boolean && Boolean.TRUE.equals(object);
+ }
+
+ public Map getExtendedData() {
+ return request.getExtendedData();
+ }
+
+ /**
+ * Checks if the current request is a creation request for a message.
+ *
+ * @return true if the current request is a creation request for message
+ */
+ public boolean isSequenceMessageCreation() {
+ boolean result = false;
+ if (!isNoteAttachmentCreationRequest() && request instanceof CreateRequest) {
+ CreateRequest createRequest = (CreateRequest) request;
+ Object tool = createRequest.getNewObject();
+ result = tool instanceof MessageCreationTool;
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/SequenceDiagramEPQuery.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/SequenceDiagramEPQuery.java
new file mode 100644
index 0000000000..5b993c79fc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/util/SequenceDiagramEPQuery.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.sequence.ui.tool.internal.util;
+
+import java.util.List;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.LifelineEditPart;
+import org.eclipse.sirius.diagram.sequence.ui.tool.internal.edit.part.SequenceDiagramEditPart;
+
+/**
+ * Queries on a sequence diagram.
+ *
+ * @author pcdavid
+ */
+public class SequenceDiagramEPQuery {
+ private final SequenceDiagramEditPart diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the diagram to query.
+ */
+ public SequenceDiagramEPQuery(SequenceDiagramEditPart diagram) {
+ this.diagram = Preconditions.checkNotNull(diagram);
+ }
+
+ public List<LifelineEditPart> getAllLifelines() {
+ return EditPartsHelper.getAllLifelines(diagram);
+ }
+}

Back to the top