Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephane Bonnet2013-09-05 14:35:04 +0000
committerStephane Bonnet2013-09-05 14:35:04 +0000
commit5cf53378e4a084aefb90d9648d5db61d83881f58 (patch)
treed1187a4a39864273af2fccfd85f6e1eb4aff07fc /plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business
downloadorg.eclipse.sirius-5cf53378e4a084aefb90d9648d5db61d83881f58.tar.gz
org.eclipse.sirius-5cf53378e4a084aefb90d9648d5db61d83881f58.tar.xz
org.eclipse.sirius-5cf53378e4a084aefb90d9648d5db61d83881f58.zip
Initial version.
Diffstat (limited to 'plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business')
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalPositionFunction.java113
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalRangeFunction.java45
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/color/DefaultColorStyleDescription.java70
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractFrame.java221
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractNodeEvent.java255
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceElement.java152
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceNode.java73
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/CombinedFragment.java211
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/EndOfLife.java140
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Execution.java468
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElement.java98
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElementAccessor.java425
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceEvent.java172
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceNode.java38
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InstanceRole.java189
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InteractionUse.java126
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Lifeline.java331
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/LostMessageEnd.java147
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Message.java552
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ObservationPoint.java139
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Operand.java330
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/SequenceDiagram.java463
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/State.java215
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/package-info.java12
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceLayout.java214
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceOrderingLayout.java168
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/EventEndToPositionFunction.java137
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/LayoutConstants.java193
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/SequenceLayout.java138
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/AbstractSequenceAbsoluteBoundsFlagger.java93
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceDiagramAbsoluteBoundsFlagger.java54
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceEventAbsoluteBoundsFlagger.java51
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/LostMessageEndHorizontalLayoutHelper.java451
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/SequenceHorizontalLayout.java656
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/observation/SequenceObservationLayout.java165
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/vertical/SequenceVerticalLayout.java1080
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/SequenceDDiagramSpec.java286
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/BasicMessageMappingSpec.java153
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CombinedFragmentMappingSpec.java209
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CreationMessageMappingSpec.java154
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/DestructionMessageMappingSpec.java154
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/EndOfLifeMappingSpec.java211
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ExecutionMappingSpec.java211
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InstanceRoleMappingSpec.java211
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InteractionUseMappingSpec.java209
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ObservationPointMappingSpec.java211
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/OperandMappingSpec.java209
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ReturnMessageMappingSpec.java154
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/SequenceDiagramDescriptionSpec.java120
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/StateMappingSpec.java211
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/tool/MessageCreationToolSpec.java42
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/CompoundEventEndSpec.java78
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/SingleEventEndSpec.java50
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/EndOfLifeMoveOperation.java53
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/FixGraphicalOrderingOperation.java73
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ISequenceNodeMoveOperation.java80
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/InverseRelativeNodePositionOperation.java54
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshGraphicalOrderingOperation.java144
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshSemanticOrderingsOperation.java173
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ReparentExecutionOperation.java78
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SequenceMessageRangeHelper.java176
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetMessageRangeOperation.java141
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetVerticalRangeOperation.java54
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ShiftDirectSubExecutionsOperation.java72
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeGraphicalOrderingOperation.java79
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeISequenceEventsSemanticOrderingOperation.java330
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeInstanceRoleSemanticOrderingOperation.java200
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/VerticalSpaceExpansion.java339
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/EventEndHelper.java220
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/RefreshOrderingHelper.java245
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceElementQuery.java80
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceEventQuery.java309
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/InstanceRoleQuery.java51
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/RangeComparator.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ReversedRangeComparator.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramDescriptionQuery.java119
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramQuery.java342
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceMessageViewQuery.java292
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceNodeQuery.java95
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/TSequenceDiagramQuery.java94
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/FixBendpointsOnCreationCommand.java266
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutCommand.java87
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutScope.java133
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutTrigger.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapter.java357
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapterScope.java85
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtension.java107
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtensionProvider.java39
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceSlidableAnchor.java45
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/tool/ToolCommandBuilder.java504
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/BendpointsHelper.java67
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/EventFinder.java239
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceElementSwitch.java579
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceEventsTreeIterator.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ParentOperandFinder.java141
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/RangeSetter.java314
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SameLifelinePredicate.java73
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SubEventsHelper.java385
98 files changed, 18844 insertions, 0 deletions
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalPositionFunction.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalPositionFunction.java
new file mode 100644
index 0000000000..9a1777daaa
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalPositionFunction.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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.business.internal;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+
+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.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.util.Range;
+
+/**
+ * A function which computes the vertical position (in absolute, normalized
+ * coordinates) of an {@link EventEnd}.
+ *
+ * @author pcdavid
+ */
+public class VerticalPositionFunction implements Function<EventEnd, 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 = Integer.MAX_VALUE;
+
+ private final SequenceDDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the diagram on which the compute the position of the ends.
+ */
+ public VerticalPositionFunction(SequenceDDiagram diagram) {
+ this.diagram = diagram;
+ }
+
+ /**
+ * Returns the vertical position of the specified end as it appears on the
+ * diagram associated to this function, or <code>INVALID_POSITION</code> if
+ * the end is invalid or is not part of the diagram.
+ *
+ * @param end
+ * the end for which to compute the position.
+ * @return the vertical position of the end, or
+ * <code>INVALID_POSITION</code>.
+ */
+ public Integer apply(EventEnd end) {
+ Integer result;
+ SingleEventEnd see = null;
+ EObject semanticEvent = null;
+ if (end instanceof SingleEventEnd) {
+ see = (SingleEventEnd) end;
+ } else if (end instanceof CompoundEventEnd) {
+ see = ((CompoundEventEnd) end).getEventEnds().iterator().next();
+ }
+
+ if (see != null) {
+ semanticEvent = see.getSemanticEvent();
+ }
+
+ Iterable<View> eventViews = ISequenceElementAccessor.getViewsForSemanticElement(diagram, semanticEvent);
+
+ if (Iterables.isEmpty(eventViews) && end instanceof CompoundEventEnd) {
+ for (SingleEventEnd see2 : ((CompoundEventEnd) end).getEventEnds()) {
+ if (see != null) {
+ semanticEvent = see2.getSemanticEvent();
+ }
+ eventViews = ISequenceElementAccessor.getViewsForSemanticElement(diagram, semanticEvent);
+ if (!Iterables.isEmpty(eventViews)) {
+ break;
+ }
+ }
+ }
+
+ if (Iterables.isEmpty(eventViews)) {
+ result = INVALID_POSITION;
+ } else {
+ result = INVALID_POSITION;
+ Range range = Range.emptyRange();
+
+ for (View potentialView : eventViews) {
+ range = VerticalRangeFunction.INSTANCE.apply(potentialView);
+ if (!range.isEmpty()) {
+ break;
+ }
+ }
+
+ if (EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(end)) {
+ result = (int) range.middleValue();
+ } else if (EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(end)) {
+ result = (int) range.middleValue();
+ } else {
+ result = (int) (see.isStart() ? range.getLowerBound() : range.getUpperBound());
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalRangeFunction.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalRangeFunction.java
new file mode 100644
index 0000000000..8a268c4925
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/VerticalRangeFunction.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.business.internal;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+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.ISequenceEvent;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Computes the absolute vertical range occupied by an element of a sequence
+ * diagram, from its GMF View.
+ *
+ * @author pcdavid
+ */
+public enum VerticalRangeFunction implements Function<View, Range> {
+ /**
+ * The default instance.
+ */
+ INSTANCE;
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range apply(View view) {
+ Range result = Range.emptyRange();
+ Option<ISequenceEvent> iSequenceEvent = ISequenceElementAccessor.getISequenceEvent(view);
+ if (iSequenceEvent.some()) {
+ result = iSequenceEvent.get().getVerticalRange();
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/color/DefaultColorStyleDescription.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/color/DefaultColorStyleDescription.java
new file mode 100644
index 0000000000..dc5f785205
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/color/DefaultColorStyleDescription.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.business.internal.color;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.diagram.sequence.template.TExecutionStyle;
+import org.eclipse.sirius.diagram.sequence.template.TLifelineStyle;
+import org.eclipse.sirius.diagram.sequence.template.TMessageStyle;
+import org.eclipse.sirius.diagram.sequence.template.util.TemplateSwitch;
+import org.eclipse.sirius.tools.api.ui.color.EnvironmentSystemColorFactory;
+
+/**
+ * Class responsible for setting default color values on style descriptions.
+ *
+ * @author mporhel
+ *
+ */
+public class DefaultColorStyleDescription extends TemplateSwitch<EObject> {
+
+ private static final String BLACK = "black";
+
+ private static final String GRAY = "gray";
+
+ /**
+ * Set the default color descriptions on the given EObject.
+ *
+ * @param theEObject
+ * the object to update.
+ */
+ public void setDefaultColors(final EObject theEObject) {
+ doSwitch(theEObject);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EObject caseTLifelineStyle(TLifelineStyle object) {
+ object.setLifelineColor(EnvironmentSystemColorFactory.getDefault().getSystemColorDescription(BLACK));
+ return super.caseTLifelineStyle(object);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EObject caseTExecutionStyle(TExecutionStyle object) {
+ object.setBorderColor(EnvironmentSystemColorFactory.getDefault().getSystemColorDescription(BLACK));
+ object.setBackgroundColor(EnvironmentSystemColorFactory.getDefault().getSystemColorDescription(GRAY));
+ return super.caseTExecutionStyle(object);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EObject caseTMessageStyle(TMessageStyle object) {
+ object.setStrokeColor(EnvironmentSystemColorFactory.getDefault().getSystemColorDescription(BLACK));
+ return super.caseTMessageStyle(object);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractFrame.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractFrame.java
new file mode 100644
index 0000000000..0f55823599
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractFrame.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.DslCommonPlugin;
+import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException;
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.profiler.ProfilerTask;
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.EventFinder;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ParentOperandFinder;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.description.FrameMapping;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.provider.SiriusEditPlugin;
+import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
+import org.eclipse.sirius.ui.tools.api.profiler.SiriusTasks;
+
+/**
+ * Represents a frame container.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractFrame extends AbstractSequenceNode implements ISequenceEvent {
+
+ private static final ProfilerTask COVERAGE = new ProfilerTask("Sequence", "Compute interaction use coverage", SiriusEditPlugin.getPlugin().getBundledImage(SiriusTasks.IMAGES_VIEWPOINT));
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing the combined fragment.
+ */
+ AbstractFrame(Node node) {
+ super(node);
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents a frame.
+ *
+ * @return a predicate to check whether a GMF View represents a frame.
+ */
+ public static Predicate<View> notationPredicate() {
+ return Predicates.or(InteractionUse.notationPredicate(), CombinedFragment.notationPredicate());
+ }
+
+ public Rectangle getProperLogicalBounds() {
+ /*
+ * Combined Fragments are directly on the diagram itself, so we can use
+ * the raw GMF bounds as is.
+ */
+ return getRawNotationBounds();
+ }
+
+ /**
+ * Get the covered lifelines.
+ *
+ * @return the covered lifelines.
+ */
+ public Collection<Lifeline> computeCoveredLifelines() {
+ DslCommonPlugin.PROFILER.startWork(COVERAGE);
+ Collection<EObject> semLifelines = Lists.newArrayList();
+ Collection<Lifeline> coveredLifelines = Lists.newArrayList();
+
+ EObject element = getNotationNode().getElement();
+ if (element instanceof DDiagramElement && ((DDiagramElement) element).getDiagramElementMapping() instanceof FrameMapping) {
+ DDiagramElement dde = (DDiagramElement) element;
+ FrameMapping mapping = (FrameMapping) dde.getDiagramElementMapping();
+ EObject semanticInteractionUse = dde.getTarget();
+ IInterpreter interpreter = InterpreterUtil.getInterpreter(semanticInteractionUse);
+
+ if (interpreter != null && !StringUtil.isEmpty(mapping.getCoveredLifelinesExpression())) {
+ try {
+ semLifelines = interpreter.evaluateCollection(semanticInteractionUse, mapping.getCoveredLifelinesExpression());
+ } catch (final EvaluationException e) {
+ RuntimeLoggerManager.INSTANCE.error(mapping, DescriptionPackage.eINSTANCE.getFrameMapping_CoveredLifelinesExpression(), e);
+ }
+ }
+ }
+
+ Collection<Lifeline> allLifelines = Lists.newArrayList(getDiagram().getAllLifelines());
+ for (Lifeline lifeline : allLifelines) {
+ EObject sem = ISequenceElement.SEMANTIC_TARGET.apply(lifeline);
+ if (semLifelines.contains(sem)) {
+ coveredLifelines.add(lifeline);
+ }
+ }
+
+ DslCommonPlugin.PROFILER.stopWork(COVERAGE);
+ return coveredLifelines;
+ }
+
+ /**
+ * Get the covered lifelines.
+ *
+ * @return the covered lifelines.
+ */
+ public Collection<ISequenceEvent> computeParentEvents() {
+ Collection<Lifeline> coveredLifelines = computeCoveredLifelines();
+ return computeParentEvents(coveredLifelines);
+ }
+
+ /**
+ * Get the covered lifelines.
+ *
+ * @param coveredLifelines
+ * a collection of lifelines that should be a subset of computed
+ * lifelines (NO CHECK)
+ *
+ * @return the covered lifelines.
+ */
+ public Collection<ISequenceEvent> computeParentEvents(Collection<Lifeline> coveredLifelines) {
+ Collection<ISequenceEvent> parentEvents = Sets.newHashSet();
+ for (Lifeline lifeline : coveredLifelines) {
+ EventFinder finder = new EventFinder(lifeline);
+ finder.setEventsToIgnore(Predicates.equalTo((ISequenceEvent) this));
+ ISequenceEvent localParent = finder.findMostSpecificEvent(this.getVerticalRange());
+ if (localParent != null && localParent.getVerticalRange().includes(this.getVerticalRange())) {
+ parentEvents.add(localParent);
+ }
+ }
+ return parentEvents;
+ }
+
+ /**
+ * Combined fragments are not associated to a particular lifeline.
+ * <p>
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getParentEvent() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLogicallyInstantaneous() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getOccupiedRange() {
+ return Range.emptyRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getValidSubEventsRange() {
+ return Range.emptyRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getHierarchicalParentEvent() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Operand> getParentOperand() {
+ return new ParentOperandFinder(this).getParentOperand();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ISequenceEvent> getEventsToMoveWith() {
+ return getSubEvents();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractNodeEvent.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractNodeEvent.java
new file mode 100644
index 0000000000..dcd0356359
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractNodeEvent.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+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.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ParentOperandFinder;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents an execution on a lifeline or another parent execution.
+ *
+ * @author mporhel, pcdavid, smonnier
+ */
+public abstract class AbstractNodeEvent extends AbstractSequenceNode implements ISequenceEvent {
+ /**
+ * Predicate to filter Frames and Operand from possible new parents of an
+ * execution reparent.
+ */
+ public static final Predicate<ISequenceEvent> NO_REPARENTABLE_EVENTS = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ return input instanceof AbstractFrame || input instanceof State || input instanceof Operand || input instanceof Message;
+ }
+ };
+
+ /**
+ * The visual ID. Same as a normal bordered node.
+ *
+ * see org.eclipse.sirius.diagram.internal.edit.parts.DNode2EditPart.
+ * VISUAL_ID
+ */
+ public static final int VISUAL_ID = 3001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * execution.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return (AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getExecutionMapping()) || AbstractSequenceElement.isSequenceDiagramElement(input,
+ DescriptionPackage.eINSTANCE.getStateMapping())) && !InstanceRole.viewpointElementPredicate().apply((DDiagramElement) input.eContainer());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing this execution.
+ */
+ AbstractNodeEvent(Node node) {
+ super(node);
+ Preconditions.checkArgument(AbstractNodeEvent.notationPredicate().apply(node), "The node does not represent an AbstractNodeEvent.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an execution.
+ *
+ * @return a predicate to check whether a GMF View represents an execution.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, AbstractNodeEvent.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getParentEvent() {
+ ISequenceEvent parent = getHierarchicalParentEvent();
+
+ List<ISequenceEvent> potentialSiblings = parent.getSubEvents();
+ if (!potentialSiblings.contains(this)) {
+ // look for parentOperand
+ parent = getParentOperand().get();
+ }
+ return parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getHierarchicalParentEvent() {
+ EObject viewContainer = this.view.eContainer();
+ if (viewContainer instanceof View) {
+ View parentView = (View) viewContainer;
+ Option<ISequenceEvent> parentElement = ISequenceElementAccessor.getISequenceEvent(parentView);
+ if (parentElement.some()) {
+ return parentElement.get();
+ }
+ }
+ throw new RuntimeException("Invalid context for execution " + this);
+ }
+
+ /**
+ * Finds the deepest Operand container including the position if existing.
+ *
+ * @param verticalPosition
+ * the position where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ public Option<Operand> getParentOperand(final int verticalPosition) {
+ return new ParentOperandFinder(this).getParentOperand(new Range(verticalPosition, verticalPosition));
+ }
+
+ /**
+ * Finds the deepest Operand container including the position if existing.
+ *
+ * @param range
+ * the range where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ public Option<Operand> getParentOperand(final Range range) {
+ return new ParentOperandFinder(this).getParentOperand(range);
+ }
+
+ /**
+ * Finds the deepest Operand container if existing.
+ *
+ * @return the deepest Operand container if existing
+ */
+ public Option<Operand> getParentOperand() {
+ return new ParentOperandFinder(this).getParentOperand();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getVerticalRange() {
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLogicallyInstantaneous() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return getParentLifeline();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ ISequenceEvent parent = getHierarchicalParentEvent();
+ Rectangle parentLogicalBounds = parent.getProperLogicalBounds();
+
+ Point location = getProperLogicalLocation(parent, bounds, parentLogicalBounds);
+ Dimension size = new Dimension(bounds.getWidth(), bounds.getHeight());
+ return new Rectangle(location, size);
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ private Point getProperLogicalLocation(ISequenceEvent parent, Bounds bounds, Rectangle parentLogicalBounds) {
+ int x = parentLogicalBounds.x;
+ int y = parentLogicalBounds.y + bounds.getY();
+
+ if (Lifeline.notationPredicate().apply(parent.getNotationView()) || this instanceof State) {
+ /*
+ * Top-level executions which are directly on a lifeline are
+ * horizontally centered on the lifeline.
+ */
+ Point top = parentLogicalBounds.getTop();
+ int width = bounds.getWidth();
+ x = top.x - width / 2;
+ } else {
+ /*
+ * Sub-executions horizontally overlap partially their parent
+ * execution of IBorderItemOffsets.DEFAULT_OFFSET.width. We can not
+ * depend on that type here (it is in a UI plug-in, but we use its
+ * value: 8 pixels.
+ */
+ Point topRight = parentLogicalBounds.getTopRight();
+ x = topRight.x - 5;
+ }
+ return new Point(x, y);
+ }
+
+ /**
+ * Returns all the messages linked to one of the sides (top or bottom) of
+ * this execution. The resulting list can be:
+ * <ul>
+ * <li>empty, meaning there is no messages linked to any of this execution's
+ * sides.</li>
+ * <li>a list with a single element, in which case that element is the
+ * message linked to the top side of this execution.</li>
+ * <li>a list with two element, in which case the first element is the
+ * message linked to the top side of this execution and the second is the
+ * message linked to the bottom side.</li>
+ * </ul>
+ * Note that the case where there is only one linked message and it is
+ * linked to the bottom side is not supported.
+ *
+ * @return all the messages linked to one of the sides (top or bottom) of
+ * this execution.
+ */
+ public abstract List<Message> getLinkedMessages();
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceElement.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceElement.java
new file mode 100644
index 0000000000..a8aa51f7db
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceElement.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Diagram;
+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.common.tools.api.util.Options;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.business.api.query.DiagramElementMappingQuery;
+import org.eclipse.sirius.description.DiagramElementMapping;
+
+/**
+ * Partial abstract implementation of {@link ISequenceElement}.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractSequenceElement extends AdapterImpl implements ISequenceElement {
+ /**
+ * The underlying GMF View.
+ */
+ protected final View view;
+
+ /**
+ * Constructor.
+ *
+ * @param view
+ * the underlying GMF View.
+ */
+ AbstractSequenceElement(View view) {
+ this.view = Preconditions.checkNotNull(view);
+ }
+
+ /**
+ * Generic test function used by all the more specific predicates: checks
+ * that a diagram element is valid, is part of a sequence diagram, and has
+ * the specified type of mapping (or a sub-type).
+ *
+ * This method handle edge mapping imports.
+ *
+ * @param element
+ * {@link DDiagramElement}
+ * @param mappingType
+ * type of the mapping
+ *
+ * @return true is element is a sequence diagram element
+ */
+ protected static final boolean isSequenceDiagramElement(DDiagramElement element, EClass mappingType) {
+ Preconditions.checkNotNull(mappingType);
+ if (element == null || element.getDiagramElementMapping() == null) {
+ return false;
+ } else {
+ DiagramElementMapping mappingToCheck = new DiagramElementMappingQuery(element.getDiagramElementMapping()).getRootMapping();
+ return mappingType.isInstance(mappingToCheck) && SequenceDiagram.viewpointElementPredicate().apply(element.getParentDiagram());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public View getNotationView() {
+ return view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SequenceDiagram getDiagram() {
+ Diagram gmfDiagram = view.getDiagram();
+ Option<SequenceDiagram> diagram = ISequenceElementAccessor.getSequenceDiagram(gmfDiagram);
+ assert diagram.some() : "The element is not part of a sequence diagram.";
+ return diagram.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return view.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ boolean result = false;
+ if (this == obj) {
+ result = true;
+ } else if (obj != null && getClass().equals(obj.getClass())) {
+ AbstractSequenceElement other = (AbstractSequenceElement) obj;
+ if (view != null && view.equals(other.view)) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<EObject> getSemanticTargetElement() {
+ if (view.getElement() instanceof DSemanticDecorator) {
+ return Options.newSome(((DSemanticDecorator) view.getElement()).getTarget());
+ } else {
+ return Options.newNone();
+ }
+ }
+
+ /**
+ * Tries to find a lifeline among the ancestors of this element (including
+ * the element itself).
+ *
+ * @return option on the parent lifeline of this sequenceElement
+ */
+ protected Option<Lifeline> getParentLifeline() {
+ View current = view;
+ do {
+ Option<Lifeline> lifeline = ISequenceElementAccessor.getLifeline(current);
+ if (lifeline.some()) {
+ return lifeline;
+ } else {
+ current = (View) current.eContainer();
+ }
+ } while (current != null && !(current instanceof Diagram));
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "#<" + getClass().getSimpleName() + ": " + view.getElement() + ">";
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceNode.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceNode.java
new file mode 100644
index 0000000000..22d2959d9c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/AbstractSequenceNode.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.ui.tools.api.util.GMFNotationHelper;
+
+/**
+ * Abstract base class for sequence elements which are represented by a GMF
+ * Node.
+ *
+ * @author mporhel, pcdavid
+ */
+abstract class AbstractSequenceNode extends AbstractSequenceElement implements ISequenceNode {
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing this element.
+ */
+ AbstractSequenceNode(Node node) {
+ super(node);
+ }
+
+ /**
+ * Convenience method to return the underlying GMF View as a Node.
+ *
+ * @return the GMF Node representing this element.
+ */
+ public Node getNotationNode() {
+ return (Node) view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getBounds() {
+ Node node = getNotationNode();
+ if (!(node.getElement() instanceof DDiagramElement)) {
+ return null;
+ } else {
+ Point absLoc = GMFNotationHelper.getAbsoluteLocation(node);
+ int width = GMFNotationHelper.getWidth(node);
+ int height = GMFNotationHelper.getHeight(node);
+ return new Rectangle(absLoc.x, absLoc.y, width, height);
+ }
+ }
+
+ /**
+ * Returns the raw bounds of this element as stored in the GMF Node.
+ */
+ protected Rectangle getRawNotationBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ return new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/CombinedFragment.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/CombinedFragment.java
new file mode 100644
index 0000000000..0fd585ed84
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/CombinedFragment.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+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.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents a combined fragment container.
+ *
+ * @author pcdavid
+ */
+public class CombinedFragment extends AbstractFrame {
+ /**
+ * The visual ID. Same as a normal container
+ *
+ * @see DNodeContainerEditPart.VISUAL_ID.
+ */
+ public static final int VISUAL_ID = 2002;
+
+ /**
+ * The visual ID of the compartment contained by the combined fragment. It
+ * is this compartment that contains the operands.
+ *
+ * @see DNodeContainerViewNodeContainerCompartmentEditPart.VISUAL_ID.
+ */
+ public static final int COMPARTMENT_VISUAL_ID = 7001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * execution.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getCombinedFragmentMapping());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing the combined fragment.
+ */
+ CombinedFragment(Node node) {
+ super(node);
+ Preconditions.checkArgument(CombinedFragment.notationPredicate().apply(node), "The node does not represent a combined fragment.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an combined
+ * fragment.
+ *
+ * @return a predicate to check whether a GMF View represents an combined
+ * fragment.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, CombinedFragment.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an combined
+ * fragment compartment.
+ *
+ * @return a predicate to check whether a GMF View represents an combined
+ * fragment compartment.
+ */
+ public static Predicate<View> compartmentNotationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), COMPARTMENT_VISUAL_ID, CombinedFragment.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getVerticalRange() {
+ // Rectangle logicalBounds = getProperLogicalBounds();
+ // return new Range(logicalBounds.y, logicalBounds.bottom());
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return Lists.newArrayList(Iterables.filter(getOperands(), ISequenceEvent.class));
+ }
+
+ /**
+ * Get the operands of the current combined fragment.
+ *
+ * @return the operands of the current combined fragment.
+ */
+ public List<Operand> getOperands() {
+ List<Operand> result = Lists.newArrayList();
+ Predicate<View> compartementView = new Predicate<View>() {
+
+ public boolean apply(View input) {
+ return input.getType().equals(Integer.toString(COMPARTMENT_VISUAL_ID));
+ }
+ };
+ // The combined fragment contains a compartment that contains the
+ // operands
+ for (View view : Iterables.filter(Iterables.filter(this.view.eContents(), View.class), compartementView)) {
+ // Filtering compartments
+ for (View viewChild : Iterables.filter(view.eContents(), View.class)) {
+ // Filtering operands
+ Option<Operand> operand = ISequenceElementAccessor.getOperand(viewChild);
+ if (operand.some()) {
+ result.add(operand.get());
+ }
+ }
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return result;
+ }
+
+ /**
+ * Finds the operand identified by the index.
+ *
+ * @param index
+ * the position of the wanted operand
+ * @return an Option of Operand if there is an operand at the given index,
+ * an Options.newNone() otherwise
+ */
+ public Option<Operand> getOperand(int index) {
+ try {
+ return Options.newSome(getOperands().get(index));
+ } catch (IndexOutOfBoundsException e) {
+ return Options.newNone();
+ }
+ }
+
+ /**
+ * calculate the index of the operand among the list of operands in this
+ * {@link CombinedFragment}.
+ *
+ * @param operand
+ * the operand to find out its index
+ * @return the index of the operand
+ */
+ public int getIndexOfOperand(Operand operand) {
+ return getOperands().lastIndexOf(operand);
+ }
+
+ /**
+ * Finds the first operand of this {@link CombinedFragment}.
+ *
+ * @return the first operand of this {@link CombinedFragment}
+ */
+ public Operand getFirstOperand() {
+ // A combined fragment always have at least one operand
+ return getOperand(0).get();
+ }
+
+ /**
+ * Finds the last operand of this {@link CombinedFragment}.
+ *
+ * @return the last operand of this {@link CombinedFragment}
+ */
+ public Operand getLastOperand() {
+ // A combined fragment always have at least one operand
+ int lastIndex = getOperands().size() - 1;
+ return getOperand(lastIndex).get();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/EndOfLife.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/EndOfLife.java
new file mode 100644
index 0000000000..d52bba471d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/EndOfLife.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+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.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+
+/**
+ * Represents the EndOfLife marker which can appear at the bottom of a lifeline.
+ * This element can be present even in the case where the lifeline is not
+ * explicitly destroyed by a destruction message. In that case, it is used as a
+ * convenience to allow the user to resize the lifeline vertically by dragging
+ * the EndOfLife marker.
+ *
+ * @author mporhel, pcdavid
+ */
+public class EndOfLife extends AbstractSequenceNode {
+ /**
+ * The visual ID. Same as a normal bordered node.
+ *
+ * @see DNode2EditPart.VISUAL_ID
+ */
+ public static final int VISUAL_ID = 3001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * EndOfLife.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getEndOfLifeMapping());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node which represents this EOL.
+ */
+ EndOfLife(Node node) {
+ super(node);
+ Preconditions.checkArgument(EndOfLife.notationPredicate().apply(node), "The node does not represent an end-of-life.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an EndOfLife.
+ *
+ * @return a predicate to check whether a GMF View represents an EndOfLife.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, EndOfLife.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an EndOfLife.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an EndOfLife.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return getParentLifeline();
+ }
+
+ /**
+ * Returns the destruction message which targets this EOL, if any.
+ *
+ * @return the destruction message which targets this EOL, if any.
+ */
+ public Option<Message> getDestructionMessage() {
+ Node node = getNotationNode();
+ for (Edge edge : Iterables.filter(node.getTargetEdges(), Edge.class)) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(edge);
+ if (message.some() && message.get().getKind() == Message.Kind.DESTRUCTION) {
+ return message;
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ Rectangle llBounds = getLifeline().get().getProperLogicalBounds();
+ Point bottom = llBounds.getBottom();
+ int width = bounds.getWidth();
+ return new Rectangle(bottom.x - width / 2, bottom.y, bounds.getWidth(), bounds.getHeight());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Tests whether this EOL marker (and thus the associated lifeline) is
+ * explicitly destroyed by a destruction message.
+ *
+ * @return <code>true</code> if this EOL marker is the target of a
+ * destruction message.
+ */
+ public boolean isExplicitelyDestroyed() {
+ return getDestructionMessage().some();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Execution.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Execution.java
new file mode 100644
index 0000000000..ab0d8369fd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Execution.java
@@ -0,0 +1,468 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+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 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.DDiagramElement;
+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.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ParentOperandFinder;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.SubEventsHelper;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+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.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents an execution on a lifeline or another parent execution.
+ *
+ * @author mporhel, pcdavid, smonnier
+ */
+public class Execution extends AbstractNodeEvent {
+ /**
+ * Predicate to filter Frames and Operand from possible new parents of an
+ * execution reparent.
+ */
+ public static final Predicate<ISequenceEvent> NO_REPARENTABLE_EVENTS = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ return input instanceof AbstractFrame || input instanceof Operand || input instanceof Message;
+ }
+ };
+
+ /**
+ * The visual ID. Same as a normal bordered node.
+ */
+ public static final int VISUAL_ID = 3001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * execution.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getExecutionMapping())
+ && !InstanceRole.viewpointElementPredicate().apply((DDiagramElement) input.eContainer());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing this execution.
+ */
+ Execution(Node node) {
+ super(node);
+ Preconditions.checkArgument(Execution.notationPredicate().apply(node), "The node does not represent an execution.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an execution.
+ *
+ * @return a predicate to check whether a GMF View represents an execution.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, Execution.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Message> getLinkedMessages() {
+ List<Message> linkedMessages = Lists.newArrayList();
+
+ Option<Message> startMessage = getStartMessage();
+ if (startMessage.some()) {
+ linkedMessages.add(startMessage.get());
+ }
+
+ Option<Message> targetMessage = getEndMessage();
+ if (targetMessage.some()) {
+ linkedMessages.add(targetMessage.get());
+ }
+
+ return linkedMessages;
+ }
+
+ /**
+ * Returns the message linked to the start (i.e. top side) of this
+ * execution, if any.
+ *
+ * @return the message linked to the start of this execution, if any.
+ */
+ public Option<Message> getStartMessage() {
+ return getCompoundMessage(true);
+ }
+
+ private Option<Message> getCompoundMessage(boolean start) {
+ Node node = getNotationNode();
+ Set<Edge> edges = Sets.newHashSet();
+ Iterables.addAll(edges, Iterables.filter(node.getSourceEdges(), Edge.class));
+ Iterables.addAll(edges, Iterables.filter(node.getTargetEdges(), Edge.class));
+
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(this);
+ for (Edge edge : edges) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(edge);
+ if (message.some()) {
+ List<EventEnd> messageEnds = EventEndHelper.findEndsFromSemanticOrdering(message.get());
+ Iterables.retainAll(messageEnds, ends);
+ if (!messageEnds.isEmpty()) {
+ SingleEventEnd see = EventEndHelper.getSingleEventEnd(messageEnds.get(0), getSemanticTargetElement().get());
+ if (start == see.isStart()) {
+ return message;
+ }
+ }
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Returns the message linked to the end (i.e. bottom side) of this
+ * execution, if any.
+ *
+ * @return the message linked to the end of this execution, if any.
+ */
+ public Option<Message> getEndMessage() {
+ return getCompoundMessage(false);
+ }
+
+ /**
+ * Tests whether this execution starts with a reflective message.
+ *
+ * @return <code>true</code> if this execution has a reflective message
+ * linked to its start.
+ */
+ public boolean startsWithReflectiveMessage() {
+ Option<Message> startMessage = getStartMessage();
+ if (startMessage.some()) {
+ return startMessage.get().isReflective();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Tests whether this execution ends with a reflective message.
+ *
+ * @return <code>true</code> if this execution has a reflective message
+ * linked to its end.
+ */
+ public boolean endsWithReflectiveMessage() {
+ Option<Message> finishMessage = getEndMessage();
+ if (finishMessage.some()) {
+ return finishMessage.get().isReflective();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Validate that the execution is reflective. Therefore, its start message
+ * must be reflective and its return message must be null (Asynchronous
+ * message) or reflexive.
+ *
+ * @return if the execution is reflective
+ */
+ public boolean isReflective() {
+ Option<Message> startMessage = getStartMessage();
+ Option<Message> endMessage = getEndMessage();
+ return startMessage.some() && startMessage.get().isReflective() && (!endMessage.some() || endMessage.get().isReflective());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISequenceEvent getParentEvent() {
+ ISequenceEvent parent = getHierarchicalParentEvent();
+
+ List<ISequenceEvent> potentialSiblings = parent.getSubEvents();
+ if (!potentialSiblings.contains(this)) {
+ // look for parentOperand
+ parent = getParentOperand().get();
+ }
+ return parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISequenceEvent getHierarchicalParentEvent() {
+ EObject viewContainer = this.view.eContainer();
+ if (viewContainer instanceof View) {
+ View parentView = (View) viewContainer;
+ Option<ISequenceEvent> parentElement = ISequenceElementAccessor.getISequenceEvent(parentView);
+ if (parentElement.some()) {
+ return parentElement.get();
+ }
+ }
+ throw new RuntimeException("Invalid context for execution " + this);
+ }
+
+ /**
+ * Finds the deepest Operand container including the position if existing.
+ *
+ * @param verticalPosition
+ * the position where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ @Override
+ public Option<Operand> getParentOperand(final int verticalPosition) {
+ return new ParentOperandFinder(this).getParentOperand(new Range(verticalPosition, verticalPosition));
+ }
+
+ /**
+ * Finds the deepest Operand container including the position if existing.
+ *
+ * @param range
+ * the range where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ @Override
+ public Option<Operand> getParentOperand(final Range range) {
+ return new ParentOperandFinder(this).getParentOperand(range);
+ }
+
+ /**
+ * Finds the deepest Operand container if existing.
+ *
+ * @return the deepest Operand container if existing
+ */
+ @Override
+ public Option<Operand> getParentOperand() {
+ return new ParentOperandFinder(this).getParentOperand();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return new SubEventsHelper(this).getSubEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ISequenceEvent> getEventsToMoveWith() {
+ Set<ISequenceEvent> toMove = Sets.newLinkedHashSet();
+ List<ISequenceEvent> subEvents = getSubEvents();
+ toMove.addAll(findLinkedExecutions(subEvents));
+ toMove.addAll(getLinkedMessages());
+ toMove.addAll(findCoveredExecutions(subEvents));
+ toMove.addAll(subEvents);
+ return toMove;
+ }
+
+ private Collection<? extends ISequenceEvent> findLinkedExecutions(List<ISequenceEvent> subEvents) {
+ Set<Execution> linkedExecutions = Sets.newLinkedHashSet();
+ for (Message message : Iterables.filter(subEvents, Message.class)) {
+ if (this.equals(message.getSourceElement()) && message.getTargetElement() instanceof Execution) {
+ Execution targetExecution = (Execution) message.getTargetElement();
+ for (CompoundEventEnd messageCompoundEventEnd : Iterables.filter(EventEndHelper.findEndsFromSemanticOrdering(message), CompoundEventEnd.class)) {
+ for (CompoundEventEnd executionCompoundEventEnd : Iterables.filter(EventEndHelper.findEndsFromSemanticOrdering(targetExecution), CompoundEventEnd.class)) {
+ if (messageCompoundEventEnd.equals(executionCompoundEventEnd)) {
+ if (!this.equals(targetExecution)) {
+ linkedExecutions.add(targetExecution);
+ }
+ }
+ }
+ }
+ }
+ }
+ return linkedExecutions;
+ }
+
+ private Collection<? extends ISequenceEvent> findCoveredExecutions(List<ISequenceEvent> subEvents) {
+ Collection<Execution> coveredExecutions = Lists.newArrayList();
+ for (AbstractFrame frame : Iterables.filter(subEvents, AbstractFrame.class)) {
+ Collection<ISequenceEvent> parentEvents = frame.computeParentEvents();
+ parentEvents.remove(this);
+ Iterables.addAll(coveredExecutions, Iterables.filter(parentEvents, Execution.class));
+ }
+ return coveredExecutions;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range getVerticalRange() {
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLogicallyInstantaneous() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Lifeline> getLifeline() {
+ return getParentLifeline();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return new SubEventsHelper(this).canChildOccupy(child, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return new SubEventsHelper(this).canChildOccupy(child, range, eventsToIgnore, lifelines);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getOccupiedRange() {
+ return new ISequenceEventQuery(this).getOccupiedRange();
+ }
+
+ /**
+ * Sub-events can occur anywhere on a normal execution as long as it is
+ * strictly inside.
+ * <p>
+ * {@inheritDoc}
+ */
+ public Range getValidSubEventsRange() {
+ Range range = getVerticalRange();
+ if (range.width() > 2 * LayoutConstants.EXECUTION_CHILDREN_MARGIN) {
+ return range.shrinked(LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+ } else {
+ return range;
+ }
+ }
+
+ /**
+ * Finds all linked executions (by messages with CompoundEventEnd) from
+ * executionEditPart. Depending on the value of investigateRecursively, it
+ * will recursively investigate the linked execution.
+ *
+ * @param recurse
+ * investigate recursively if true
+ * @return the list of linked {@link Execution} from executionEditPart
+ * @deprecated
+ */
+ @Deprecated
+ public List<Execution> findLinkedExecutions(boolean recurse) {
+ List<Execution> impactedExecutions = Lists.newArrayList();
+ findLinkedExecutions(impactedExecutions, this, recurse);
+ return impactedExecutions;
+ }
+
+ /**
+ * Recursive function of the previous one that add the result in the
+ * parameter list impactedExecutionEditPart.
+ *
+ * @param impactedExecutioExecutions
+ * the list of linked {@link Execution} from executionEditPart
+ * @param execution
+ * the current {@link Execution}
+ * @param recurse
+ * investigate recursively if true
+ */
+ private void findLinkedExecutions(List<Execution> impactedExecutions, Execution execution, boolean recurse) {
+ List<Message> messagesFrom = new ISequenceEventQuery(execution).getAllMessagesFrom();
+ for (Message message : messagesFrom) {
+ boolean targetsUnseenExecution = message.getTargetElement() instanceof Execution && !impactedExecutions.contains(message.getTargetElement());
+ if (targetsUnseenExecution) {
+ Execution targetExecution = (Execution) message.getTargetElement();
+ for (CompoundEventEnd messageCompoundEventEnd : Iterables.filter(EventEndHelper.findEndsFromSemanticOrdering(message), CompoundEventEnd.class)) {
+ for (CompoundEventEnd executionCompoundEventEnd : Iterables.filter(EventEndHelper.findEndsFromSemanticOrdering(targetExecution), CompoundEventEnd.class)) {
+ if (messageCompoundEventEnd.equals(executionCompoundEventEnd)) {
+ if (!impactedExecutions.contains(targetExecution)) {
+ impactedExecutions.add(targetExecution);
+ if (recurse) {
+ findLinkedExecutions(impactedExecutions, targetExecution, recurse);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the extended vertical range of this execution, i.e. the vertical
+ * range of the execution including any extensions like branches for linked
+ * start/end reflective messages. This corresponds to the range of all the
+ * elements which are tied to the execution and will move along with it when
+ * the execution is moved.
+ *
+ * @return the extended vertical range of this execution.
+ */
+ public Range getExtendedVerticalRange() {
+ Range result = getVerticalRange();
+ for (Message linkedMessage : getLinkedMessages()) {
+ // For non-reflective and non-deferred messages, this is a no-op.
+ result = result.union(linkedMessage.getVerticalRange());
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElement.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElement.java
new file mode 100644
index 0000000000..24194b9a14
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElement.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.business.internal.elements;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Function;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DSemanticDecorator;
+
+/**
+ * Common interface for all the elements of a sequence diagram.
+ *
+ * @author mporhel
+ */
+public interface ISequenceElement extends Adapter {
+
+ /**
+ * Function to get the notation view.
+ */
+ Function<ISequenceElement, View> NOTATION_VIEW = new Function<ISequenceElement, View>() {
+ public View apply(ISequenceElement from) {
+ return from.getNotationView();
+ }
+ };
+
+ /**
+ * Function to compute the semantic target element from a sequence element.
+ */
+ Function<ISequenceElement, EObject> SEMANTIC_TARGET = new Function<ISequenceElement, EObject>() {
+ public EObject apply(ISequenceElement from) {
+ EObject semantic = null;
+ View notationView = from.getNotationView();
+ if (notationView != null && notationView.getElement() instanceof DSemanticDecorator) {
+ semantic = ((DSemanticDecorator) notationView.getElement()).getTarget();
+ }
+ return semantic;
+ }
+ };
+
+ /**
+ * A function to compute the proper logical bounds a sequence element.
+ */
+ Function<ISequenceElement, Rectangle> PROPER_LOGICAL_BOUNDS = new Function<ISequenceElement, Rectangle>() {
+ public Rectangle apply(ISequenceElement from) {
+ return from.getProperLogicalBounds();
+ }
+ };
+
+ /**
+ * Returns the view corresponding to the current sequence element.
+ *
+ * @return the corresponding view.
+ */
+ View getNotationView();
+
+ /**
+ * Returns the semantic object that this element represents.
+ *
+ * @return the semantic object that this element represents.
+ */
+ Option<EObject> getSemanticTargetElement();
+
+ /**
+ * Returns the sequence diagram this element is part of.
+ *
+ * @return the sequence diagram this element is part of.
+ */
+ SequenceDiagram getDiagram();
+
+ /**
+ * Return an option referencing the current lifeline of the current sequence
+ * event.
+ *
+ * @return the lifeline of the current node.
+ */
+ Option<Lifeline> getLifeline();
+
+ /**
+ * Returns the logical bounds of this element itself, excluding any attached
+ * element (sub-executions, message branches...).
+ *
+ * @return the logical bounds of this element itself.
+ */
+ Rectangle getProperLogicalBounds();
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElementAccessor.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElementAccessor.java
new file mode 100644
index 0000000000..4b73924803
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceElementAccessor.java
@@ -0,0 +1,425 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+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.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+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.common.tools.api.util.Options;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.DSemanticDiagram;
+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.SequenceDDiagram;
+
+/**
+ * Accessor to get the sequence element corresponding to a notation one.
+ *
+ * @author mporhel
+ *
+ */
+public final class ISequenceElementAccessor {
+ /**
+ * Avoid instanciation
+ */
+ private ISequenceElementAccessor() {
+
+ }
+
+ /**
+ * TODO Comment.
+ *
+ * @param notationView
+ * .
+ * @return .
+ */
+ public static Option<ISequenceElement> getISequenceElement(View notationView) {
+ return ISequenceElementAccessor.getOrCreate(notationView, ISequenceElement.class);
+ }
+
+ /**
+ * TODO Comment.
+ *
+ * @param diagramView
+ * .
+ * @return .
+ */
+ public static Option<SequenceDiagram> getSequenceDiagram(Diagram diagramView) {
+ return ISequenceElementAccessor.getOrCreate(diagramView, SequenceDiagram.class);
+ }
+
+ /**
+ * TODO COmment.
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<ISequenceEvent> getISequenceEvent(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, ISequenceEvent.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<ISequenceNode> getISequenceNode(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, ISequenceNode.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<InstanceRole> getInstanceRole(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, InstanceRole.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<Lifeline> getLifeline(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, Lifeline.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<EndOfLife> getEndOfLife(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, EndOfLife.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<AbstractNodeEvent> getAbstractNodeEvent(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, AbstractNodeEvent.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<Execution> getExecution(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, Execution.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<State> getState(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, State.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<Message> getMessage(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, Message.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<InteractionUse> getInteractionUse(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, InteractionUse.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<CombinedFragment> getCombinedFragment(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, CombinedFragment.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<Operand> getOperand(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, Operand.class);
+ }
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<LostMessageEnd> getLostMessageEnd(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, LostMessageEnd.class);
+ }
+
+
+ /**
+ * .
+ *
+ * @param view
+ * .
+ * @return .
+ */
+ public static Option<ObservationPoint> getObservationPoint(View view) {
+ return ISequenceElementAccessor.getOrCreate(view, ObservationPoint.class);
+ }
+
+ /**
+ * Get the existing {@link ISequenceElement} corresponding to the given View
+ * or create it.
+ *
+ * @param notationView
+ * the notation view.
+ * @return existing or new {@link ISequenceElement}.
+ */
+ private static <T extends ISequenceElement> Option<T> getOrCreate(View notationView, Class<T> expectedType) {
+ T ise = null;
+
+ if (notationView != null) {
+ Iterator<ISequenceElement> it = Iterators.filter(notationView.eAdapters().iterator(), ISequenceElement.class);
+ if (it.hasNext()) {
+ ISequenceElement seqElt = it.next();
+ if (expectedType.isInstance(seqElt)) {
+ ise = expectedType.cast(seqElt);
+ }
+ } else {
+ ISequenceElement element = ISequenceElementAccessor.createSequenceElement(notationView);
+ if (element != null && expectedType.isInstance(element)) {
+ ise = expectedType.cast(element);
+ }
+ }
+ }
+ return Options.newSome(ise);
+ }
+
+ private static ISequenceElement createSequenceElement(View notationView) {
+ ISequenceElement created = null;
+ if (SequenceDiagram.notationPredicate().apply(notationView)) {
+ created = new SequenceDiagram((Diagram) notationView);
+ } else if (InstanceRole.notationPredicate().apply(notationView)) {
+ created = new InstanceRole((Node) notationView);
+ } else if (Lifeline.notationPredicate().apply(notationView)) {
+ created = new Lifeline((Node) notationView);
+ } else if (EndOfLife.notationPredicate().apply(notationView)) {
+ created = new EndOfLife((Node) notationView);
+ } else if (Execution.notationPredicate().apply(notationView)) {
+ created = new Execution((Node) notationView);
+ } else if (State.notationPredicate().apply(notationView)) {
+ created = new State((Node) notationView);
+ } else if (Message.notationPredicate().apply(notationView)) {
+ created = new Message((Edge) notationView);
+ } else if (CombinedFragment.notationPredicate().apply(notationView)) {
+ created = new CombinedFragment((Node) notationView);
+ } else if (Operand.notationPredicate().apply(notationView)) {
+ created = new Operand((Node) notationView);
+ } else if (InteractionUse.notationPredicate().apply(notationView)) {
+ created = new InteractionUse((Node) notationView);
+ } else if (LostMessageEnd.notationPredicate().apply(notationView)) {
+ created = new LostMessageEnd((Node) notationView);
+ } else if (ObservationPoint.notationPredicate().apply(notationView)) {
+ created = new ObservationPoint((Node) notationView);
+ }
+
+ if (created != null) {
+ notationView.eAdapters().add(created);
+ }
+ return created;
+ }
+
+ /**
+ * 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<ISequenceEvent> getEventsForSemanticElement(SequenceDiagram diagram, EObject semanticElement) {
+ ECrossReferenceAdapter xref = ISequenceElementAccessor.getCrossReferencer(semanticElement);
+ if (xref == null) {
+ return Collections.emptySet();
+ } else {
+ Collection<ISequenceEvent> result = Lists.newArrayList();
+ for (Setting setting : xref.getInverseReferences(semanticElement)) {
+ if (ISequenceElementAccessor.isDiagramElementTargetReference(setting)) {
+ DDiagramElement dde = (DDiagramElement) setting.getEObject();
+ Option<View> optView = ISequenceElementAccessor.getGMFView(dde, xref);
+ if (optView.some()) {
+ Option<ISequenceEvent> elt = ISequenceElementAccessor.getISequenceEvent(optView.get());
+ if (elt.some() && diagram.equals(elt.get().getDiagram())) {
+ result.add(elt.get());
+ }
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * 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<View> getViewsForSemanticElement(SequenceDDiagram diagram, EObject semanticElement) {
+ ECrossReferenceAdapter xref = ISequenceElementAccessor.getCrossReferencer(semanticElement);
+ if (xref == null || diagram == null) {
+ return Collections.emptySet();
+ } else {
+ Collection<View> result = Lists.newArrayList();
+ for (Setting setting : xref.getInverseReferences(semanticElement)) {
+ if (ISequenceElementAccessor.isDiagramElementTargetReference(setting)) {
+ DDiagramElement dde = (DDiagramElement) setting.getEObject();
+ Option<View> optView = ISequenceElementAccessor.getGMFView(dde, xref);
+ if (optView.some() && diagram.equals(dde.getParentDiagram())) {
+ result.add(optView.get());
+ }
+ } else if (ISequenceElementAccessor.isDiagramTargetReference(setting)) {
+ DSemanticDiagram foundDiag = (DSemanticDiagram) setting.getEObject();
+ Option<View> optView = ISequenceElementAccessor.getGMFView(foundDiag, xref);
+ if (optView.some() && diagram.equals(foundDiag)) {
+ result.add(optView.get());
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * 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<DDiagramElement> getDiagramElementsForSemanticElement(SequenceDiagram diagram, EObject semanticElement) {
+ ECrossReferenceAdapter xref = ISequenceElementAccessor.getCrossReferencer(semanticElement);
+ if (xref == null) {
+ return Collections.emptySet();
+ } else {
+ Collection<DDiagramElement> result = Lists.newArrayList();
+ for (Setting setting : xref.getInverseReferences(semanticElement)) {
+ if (ISequenceElementAccessor.isDiagramElementTargetReference(setting)) {
+ result.add((DDiagramElement) setting.getEObject());
+ }
+ }
+ return result;
+ }
+ }
+
+ private static Option<View> getGMFView(DSemanticDecorator dSem, ECrossReferenceAdapter xref) {
+ for (Setting setting : xref.getInverseReferences(dSem)) {
+ if (ISequenceElementAccessor.isViewElementReference(setting)) {
+ EObject view = setting.getEObject();
+ if (view instanceof View && ((View) view).getDiagram() != null) {
+ return Options.newSome((View) view);
+ }
+ }
+ }
+ return Options.newNone();
+ }
+
+ private static boolean isViewElementReference(Setting setting) {
+ EReference elementRef = NotationPackage.eINSTANCE.getView_Element();
+ return setting.getEObject() instanceof View && setting.getEStructuralFeature().equals(elementRef);
+ }
+
+ private static boolean isDiagramElementTargetReference(Setting setting) {
+ EReference targetReference = SiriusPackage.eINSTANCE.getDSemanticDecorator_Target();
+ return setting.getEObject() instanceof DDiagramElement && setting.getEStructuralFeature().equals(targetReference);
+ }
+
+ private static boolean isDiagramTargetReference(Setting setting) {
+ EReference targetReference = SiriusPackage.eINSTANCE.getDSemanticDecorator_Target();
+ return setting.getEObject() instanceof DDiagram && 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;
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceEvent.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceEvent.java
new file mode 100644
index 0000000000..55ec6ff46b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceEvent.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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * 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 mporhel
+ */
+public interface ISequenceEvent extends ISequenceElement {
+
+ /**
+ * Predicate to test all notation predicate of existing sequence events.
+ */
+ @SuppressWarnings("unchecked")
+ Predicate<View> ISEQUENCEEVENT_NOTATION_PREDICATE = Predicates.or(AbstractNodeEvent.notationPredicate(), Message.notationPredicate(), InteractionUse.notationPredicate(),
+ CombinedFragment.notationPredicate(), Operand.notationPredicate());
+
+ /**
+ * A function to compute the vertical range a sequence event.
+ */
+ Function<ISequenceEvent, Range> VERTICAL_RANGE = new Function<ISequenceEvent, Range>() {
+ public Range apply(ISequenceEvent from) {
+ return from.getVerticalRange();
+ }
+ };
+
+ /**
+ * Tests whether this event should be considered logically to be
+ * instantaneous. Depending on its graphical representation, it may still
+ * cover a significant vertical space.
+ *
+ * @return <code>true</code> if this event should be considered
+ * instantaneous.
+ */
+ boolean isLogicallyInstantaneous();
+
+ /**
+ * Returns the vertical range of coordinates this event covers. The
+ * coordinates are normalized y coordinates (relative to the origin of the
+ * logical plane, whatever the scroll state is, and independent of the zoom
+ * level).
+ *
+ * @return the vertical range of coordinates this event covers.
+ */
+ Range getVerticalRange();
+
+ /**
+ * Set the vertical range of this sequence event.
+ *
+ * @param range
+ * the new vertical range.
+ * @throws IllegalStateException
+ * if range is not valid.
+ */
+ void setVerticalRange(Range range) throws IllegalStateException;
+
+ /**
+ * Returns the parent event of this event (from a business point of view),
+ * if any. Returns <code>null</code> for top-level events, i.e. lifelines.
+ *
+ * @return the parent event of this event, if any.
+ */
+ ISequenceEvent getParentEvent();
+
+ /**
+ * Returns the hierarchical parent event of this event (from a Notation
+ * point of view), if any. Returns <code>null</code> for top-level events
+ * i.e. lifelines / frames / messages.
+ *
+ * @return the hierarchical parent event of this event, if any.
+ */
+ ISequenceEvent getHierarchicalParentEvent();
+
+ /**
+ * Returns the list of direct sub-events of this event, in chronological
+ * (and thus also graphical) order. This includes both events which are
+ * directly owned by this event (e.g. the messages sent by an execution) and
+ * events not owned but connected to this event (e.g. the messages received
+ * by an execution).
+ *
+ * @return the list of direct sub-events of this event, in chronological
+ * order.
+ */
+ List<ISequenceEvent> getSubEvents();
+
+ /**
+ * Returns the vertical range of coordinates inside which direct sub-events
+ * of this event can be. The coordinates are normalized y coordinates. The
+ * range returned is guaranteed to be a sub-range of
+ * {@link #getVerticalRange()} or the empty range for events which can not
+ * have children.
+ *
+ * @return the vertical range in
+ */
+ Range getValidSubEventsRange();
+
+ /**
+ * Tests whether a given child can be placed anywhere in the specified
+ * vertical range.
+ *
+ * @param child
+ * the child.
+ * @param range
+ * the vertical range to test.
+ * @return <code>true</code> if the child can be placed anywhere inside the
+ * specified vertical range (including occupying the whole range).
+ */
+ boolean canChildOccupy(ISequenceEvent child, Range range);
+
+ /**
+ * Tests whether a given child can be placed anywhere in the specified
+ * vertical range.
+ *
+ * @param child
+ * the child.
+ * @param range
+ * the vertical range to test.
+ * @param eventsToIgnore
+ * the list of events to ignore while computing canChildOccupy.
+ * @param lifelines
+ * lifelines to inspect.
+ * @return <code>true</code> if the child can be placed anywhere inside the
+ * specified vertical range (including occupying the whole range).
+ */
+ boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines);
+
+ /**
+ * Calculate the maximal occupied range of this event.
+ *
+ * @return the maximal range occupied by children of this event, from the
+ * beginning of the first sub-event to the end of the last one.
+ */
+ Range getOccupiedRange();
+
+ /**
+ * Finds the deepest Operand container if existing.
+ *
+ * @return the deepest Operand container if existing.
+ */
+ Option<Operand> getParentOperand();
+
+ /**
+ * Elements whcih should move with current events.
+ *
+ * @return a collection of elements moved with the current event.
+ */
+ Collection<ISequenceEvent> getEventsToMoveWith();
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceNode.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceNode.java
new file mode 100644
index 0000000000..3f0626416e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ISequenceNode.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Node;
+
+/**
+ * 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 mporhel
+ */
+public interface ISequenceNode extends ISequenceElement {
+ /**
+ * Convenience method to return the underlying GMF View as a Node.
+ *
+ * @return the GMF Node representing this element.
+ */
+ Node getNotationNode();
+
+ /**
+ * .
+ *
+ * @return .
+ */
+ Rectangle getBounds();
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InstanceRole.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InstanceRole.java
new file mode 100644
index 0000000000..59ae7a607e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InstanceRole.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+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.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DRepresentationElement;
+import org.eclipse.sirius.RGBValues;
+import org.eclipse.sirius.business.api.query.NodeStyleQuery;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+
+/**
+ * Represents the instance role node at the top of a lifeline.
+ *
+ * @author mporhel, pcdavid
+ */
+public class InstanceRole extends AbstractSequenceNode {
+
+ /**
+ * The visual ID. Same as a normal node.
+ */
+ public static final int VISUAL_ID = 2001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * instance role.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getInstanceRoleMapping());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing this instance role.
+ */
+ InstanceRole(Node node) {
+ super(node);
+ Preconditions.checkArgument(InstanceRole.notationPredicate().apply(node), "The node does not represent an instance role.");
+
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an instance
+ * role.
+ *
+ * @return a predicate to check whether a GMF View represents an instance
+ * role.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, InstanceRole.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an instance role.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an instance role.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * Tests whether the instance role is explicitly created by a creation
+ * message, or if it starts from the beginning of the sequence.
+ *
+ * @return <code>true</code> if the instance role is explicitly created by a
+ * creation message.
+ */
+ public boolean isExplicitlyCreated() {
+ return getCreationMessage().some();
+ }
+
+ /**
+ * Locate the creation message which creates the instance role, if any.
+ *
+ * @return the creation message which creates the instance role, if any.
+ */
+ public Option<Message> getCreationMessage() {
+ Node node = getNotationNode();
+ for (Edge edge : Iterables.filter(node.getTargetEdges(), Edge.class)) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(edge);
+ if (message.some() && message.get().getKind() == Message.Kind.CREATION) {
+ return message;
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ for (View child : Iterables.filter(getNotationView().getChildren(), View.class)) {
+ Option<Lifeline> lifeline = ISequenceElementAccessor.getLifeline(child);
+ if (lifeline.some()) {
+ return lifeline;
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ return new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Return the name of the DRepresentationElement associated to this Instance
+ * role.
+ *
+ * @return the name of the DRepresentationElement associated to this
+ * Instance role
+ */
+ public String getName() {
+ EObject targetElement = getNotationNode().getElement();
+ if (targetElement instanceof DRepresentationElement) {
+ return ((DRepresentationElement) targetElement).getName();
+ }
+ return "";
+ }
+
+ /**
+ * Return the background color of the style of the DRepresentationElement
+ * associated to this Instance role.
+ *
+ * @return the background color of the style of the DRepresentationElement
+ * associated to this Instance role.
+ */
+ public Option<RGBValues> getBackgroundColor() {
+ EObject targetElement = getNotationNode().getElement();
+ if (targetElement instanceof DNode) {
+ return new NodeStyleQuery(((DNode) targetElement).getOwnedStyle()).getBackgroundColor();
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Return the label color of the style of the DRepresentationElement
+ * associated to this Instance role.
+ *
+ * @return the label color of the style of the DRepresentationElement
+ * associated to this Instance role.
+ */
+ public Option<RGBValues> getLabelColor() {
+ EObject targetElement = getNotationNode().getElement();
+ if (targetElement instanceof DNode) {
+ return new NodeStyleQuery(((DNode) targetElement).getOwnedStyle()).getLabelColor();
+ }
+ return Options.newNone();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InteractionUse.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InteractionUse.java
new file mode 100644
index 0000000000..1561d2449a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/InteractionUse.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents an interaction use / reference.
+ *
+ * @author pcdavid
+ */
+public class InteractionUse extends AbstractFrame {
+ /**
+ * The visual ID. Same as a normal bordered node.
+ *
+ * see org.eclipse.sirius.diagram.internal.edit.parts.
+ * DNodeContainerEditPart.VISUAL_ID
+ */
+ public static final int VISUAL_ID = 2002;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * execution.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getInteractionUseMapping());
+ }
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing the interaction use.
+ */
+ InteractionUse(Node node) {
+ super(node);
+ Preconditions.checkArgument(InteractionUse.notationPredicate().apply(node), "The node does not represent an interaction use.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an execution.
+ *
+ * @return a predicate to check whether a GMF View represents an execution.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, InteractionUse.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getVerticalRange() {
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return false;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Lifeline.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Lifeline.java
new file mode 100644
index 0000000000..a78772a674
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Lifeline.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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+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.DDiagramElement;
+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.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ParentOperandFinder;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.SubEventsHelper;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Common interface for all the elements of a sequence diagram.
+ *
+ * @author mporhel
+ */
+public class Lifeline extends AbstractSequenceNode implements ISequenceEvent {
+ /**
+ * The visual id.
+ *
+ * @see DNode2EditPart.VISUAL_ID
+ */
+ public static final int VISUAL_ID = 3001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents a
+ * lifeline.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getExecutionMapping())
+ && InstanceRole.viewpointElementPredicate().apply((DDiagramElement) input.eContainer());
+ }
+ }
+
+ /**
+ * .
+ *
+ * @param node
+ * .
+ */
+ Lifeline(Node node) {
+ super(node);
+ Preconditions.checkArgument(Lifeline.notationPredicate().apply(node), "The node does not represent a lifeline.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents a lifeline.
+ *
+ * @return a predicate to check whether a GMF View represents a lifeline.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, Lifeline.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents a lifeline.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents a lifeline.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public InstanceRole getInstanceRole() {
+ return ISequenceElementAccessor.getInstanceRole((View) getNotationNode().eContainer()).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getVerticalRange() {
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLogicallyInstantaneous() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * Returns the0 EOL marker for this lifeline, if any. Note that the mere
+ * presence of an EOL does not mean this lifeline is explicitly destroyed,
+ * as EOLs can be used just to serve as visual hints of the end of lifelines
+ * and convenient resize handles.
+ *
+ * @return the EOL marker for this lifeline, if any.
+ */
+ public Option<EndOfLife> getEndOfLife() {
+ for (View child : Iterables.filter(getNotationView().getChildren(), View.class)) {
+ if (EndOfLife.notationPredicate().apply(child)) {
+ return ISequenceElementAccessor.getEndOfLife(child);
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return Options.newSome(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ Rectangle irBounds = getInstanceRole().getProperLogicalBounds();
+ Point bottom = irBounds.getBottom();
+ int width = bounds.getWidth();
+ return new Rectangle(bottom.x - width / 2, bottom.y, bounds.getWidth(), bounds.getHeight());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Lifelines are the root of the events hierarchy and thus have not parent.
+ * <p>
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getParentEvent() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return new SubEventsHelper(this).getSubEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ISequenceEvent> getEventsToMoveWith() {
+ return getSubEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return new SubEventsHelper(this).canChildOccupy(child, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return new SubEventsHelper(this).canChildOccupy(child, range, eventsToIgnore, lifelines);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getOccupiedRange() {
+ return new ISequenceEventQuery(this).getOccupiedRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getValidSubEventsRange() {
+ Range result = getVerticalRange();
+ if (result.width() > 2 * LayoutConstants.EXECUTION_CHILDREN_MARGIN) {
+ result = result.shrinked(LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+ }
+ return result;
+ }
+
+ /**
+ * Locate the destruction message which destroys the lifeline, if any.
+ *
+ * @return the destruction message which destroys the lifeline, if any.
+ */
+ public Option<Message> getDestructionMessage() {
+ Option<EndOfLife> optEOL = getEndOfLife();
+ if (optEOL.some()) {
+ return optEOL.get().getDestructionMessage();
+ } else {
+ return Options.newNone();
+ }
+ }
+
+ /**
+ * Tests whether the lifeline is explicitly destroyed by a destruction
+ * message, or if it goes until the end of the sequence.
+ *
+ * @return <code>true</code> if the lifeline is explicitly destroyed by a
+ * destruction message.
+ */
+ public boolean isExplicitlyDestroyed() {
+ Option<EndOfLife> optEOL = getEndOfLife();
+ if (optEOL.some()) {
+ return optEOL.get().isExplicitelyDestroyed();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Tests whether the lifeline is explicitly created by a creation message,
+ * or if it starts from the beginning of the sequence.
+ *
+ * @return <code>true</code> if the lifeline is explicitly created by a
+ * creation message.
+ */
+ public boolean isExplicitlyCreated() {
+ InstanceRole opt = getInstanceRole();
+ if (opt != null) {
+ return opt.isExplicitlyCreated();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Locate the destruction message which creates the lifeline, if any.
+ *
+ * @return the destruction message which creates the lifeline, if any.
+ */
+ public Option<Message> getCreationMessage() {
+ InstanceRole opt = getInstanceRole();
+ if (opt != null) {
+ return opt.getCreationMessage();
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Operand> getParentOperand() {
+ return getParentOperand(getVerticalRange());
+ }
+
+ /**
+ * Finds the deepest Operand container including the position if existing.
+ *
+ * @param verticalPosition
+ * the position where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ public Option<Operand> getParentOperand(final int verticalPosition) {
+ return new ParentOperandFinder(this).getParentOperand(new Range(verticalPosition, verticalPosition));
+ }
+
+ /**
+ * Finds the deepest Operand container convering the range if existing.
+ *
+ * @param range
+ * the range where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ public Option<Operand> getParentOperand(final Range range) {
+ return new ParentOperandFinder(this).getParentOperand(range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getHierarchicalParentEvent() {
+ return null;
+ }
+
+ /**
+ * Investigate recursively sub events to find all covering interaction uses.
+ *
+ * @return all interaction uses covering this lifeline recursively
+ */
+ public Collection<InteractionUse> getAllCoveringInteractionUses() {
+ Predicate<InteractionUse> interactionUseCoveringLifeline = new Predicate<InteractionUse>() {
+
+ public boolean apply(InteractionUse input) {
+ return input.computeCoveredLifelines().contains(Lifeline.this);
+ }
+ };
+ return Lists.newArrayList(Iterables.filter(getDiagram().getAllInteractionUses(), interactionUseCoveringLifeline));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/LostMessageEnd.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/LostMessageEnd.java
new file mode 100644
index 0000000000..c61fcdac68
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/LostMessageEnd.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+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 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.EdgeTarget;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+
+/**
+ * Represents the LostMEssageEnd marker which can appear at at the end of a
+ * message. This element can be present if a message do not have a starting end
+ * or a finishing end.
+ *
+ * @author mporhel
+ */
+public class LostMessageEnd extends AbstractSequenceNode {
+ /**
+ * The visual ID. Same as a standard node.
+ *
+ * see org.eclipse.sirius.diagram.internal.edit.parts.DNodeEditPart.
+ * VISUAL_ID
+ */
+ public static final int VISUAL_ID = 2001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * Lost Message End.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ boolean result = AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getNodeMapping());
+ if (input instanceof EdgeTarget) {
+ EdgeTarget et = (EdgeTarget) input;
+ result = result && Iterables.any(Iterables.concat(et.getIncomingEdges(), et.getOutgoingEdges()), Message.viewpointElementPredicate());
+ }
+
+ List<Predicate<DDiagramElement>> potentialMessageTarget = Lists.newArrayList();
+ potentialMessageTarget.add(EndOfLife.viewpointElementPredicate());
+ potentialMessageTarget.add(AbstractNodeEvent.viewpointElementPredicate());
+ potentialMessageTarget.add(Lifeline.viewpointElementPredicate());
+ potentialMessageTarget.add(InstanceRole.viewpointElementPredicate());
+
+ result = result && !Predicates.or(potentialMessageTarget).apply(input);
+
+ return result;
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node which represents this Lost Message End.
+ */
+ LostMessageEnd(Node node) {
+ super(node);
+ Preconditions.checkArgument(LostMessageEnd.notationPredicate().apply(node), "The node does not represent an lost message end.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an Lost Message End.
+ *
+ * @return a predicate to check whether a GMF View represents an Lost Message End.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, LostMessageEnd.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an EndOfLife.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an EndOfLife.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * Returns the message which references this lost end.
+ *
+ * @return the message which references this lost end.
+ */
+ public Option<Message> getMessage() {
+ Message msg = null;
+ Node node = getNotationNode();
+ Iterable<Edge> srcEdges = Iterables.filter(node.getSourceEdges(), Edge.class);
+ Iterable<Edge> tgtEdges = Iterables.filter(node.getTargetEdges(), Edge.class);
+ for (Edge edge : Iterables.concat(srcEdges, tgtEdges)) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(edge);
+ if (message.some()) {
+ msg = message.get();
+ break;
+ }
+ }
+
+ return Options.newSome(msg);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ return new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Message.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Message.java
new file mode 100644
index 0000000000..098206e1a7
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Message.java
@@ -0,0 +1,552 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+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 com.google.common.collect.Ordering;
+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.DDiagramElement;
+import org.eclipse.sirius.DEdge;
+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.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceMessageViewQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEndsOrdering;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Common interface for all the elements of a sequence diagram.
+ *
+ * @author mporhel
+ */
+public class Message extends AbstractSequenceElement implements ISequenceEvent {
+ /**
+ * Predicate to filter States, Frames and Operand from possible new source
+ * or target of a message reconnection.
+ */
+ public static final Predicate<ISequenceEvent> NO_RECONNECTABLE_EVENTS = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ return input instanceof AbstractFrame || input instanceof Operand || input instanceof State;
+ }
+ };
+
+ /**
+ * Function to get the Sirius DDiagramElement message kind.
+ */
+ public static final Function<DEdge, Kind> VIEWPOINT_MESSAGE_KIND = new Function<DEdge, Kind>() {
+ public Kind apply(DEdge from) {
+ Kind result = null;
+ if (AbstractSequenceElement.isSequenceDiagramElement(from, DescriptionPackage.eINSTANCE.getBasicMessageMapping())) {
+ result = Kind.BASIC;
+ } else if (AbstractSequenceElement.isSequenceDiagramElement(from, DescriptionPackage.eINSTANCE.getReturnMessageMapping())) {
+ result = Kind.REPLY;
+ } else if (AbstractSequenceElement.isSequenceDiagramElement(from, DescriptionPackage.eINSTANCE.getCreationMessageMapping())) {
+ result = Kind.CREATION;
+ } else if (AbstractSequenceElement.isSequenceDiagramElement(from, DescriptionPackage.eINSTANCE.getDestructionMessageMapping())) {
+ result = Kind.DESTRUCTION;
+ }
+ assert result != null : "Unsupported kind of message detected";
+ return result;
+ }
+ };
+
+ /**
+ * The visual ID.
+ *
+ * see org.eclipse.sirius.diagram.internal.edit.parts.DEdgeEditPart.
+ * VISUAL_ID
+ */
+ public static final int VISUAL_ID = 4001;
+
+ /**
+ * The different (exclusive) kinds of sequence messages.
+ */
+ public enum Kind {
+ /**
+ * Normal, basic message.
+ */
+ BASIC,
+ /**
+ * Reply message, associated to the basic message to which it replies.
+ */
+ REPLY,
+ /**
+ * Creation message.
+ */
+ CREATION,
+ /**
+ * Destruction message.
+ */
+ DESTRUCTION;
+ }
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents a
+ * message.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getMessageMapping());
+ }
+ }
+
+ /**
+ * .
+ *
+ * @param edge
+ * .
+ */
+ public Message(Edge edge) {
+ super(edge);
+ Preconditions.checkArgument(Message.notationPredicate().apply(edge), "The edge does not represent a sequence message.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents a message.
+ *
+ * @return a predicate to check whether a GMF View represents a message.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getEdge(), VISUAL_ID, Message.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents a message.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents a message.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Edge getNotationEdge() {
+ return (Edge) view;
+ }
+
+ /**
+ * Returns the precise kind of this message, if this element is valid.
+ *
+ * @return the precise kind of this message, if this element is valid.
+ */
+ public Kind getKind() {
+ EObject element = view.getElement();
+ if (element instanceof DEdge) {
+ return VIEWPOINT_MESSAGE_KIND.apply((DEdge) element);
+ } else {
+ // Assume basic message
+ return Kind.BASIC;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceNode getSourceElement() {
+ return ISequenceElementAccessor.getISequenceNode(getNotationEdge().getSource()).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceNode getTargetElement() {
+ return ISequenceElementAccessor.getISequenceNode(getNotationEdge().getTarget()).get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getVerticalRange() {
+ return new SequenceMessageViewQuery(getNotationEdge()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLogicallyInstantaneous() {
+ return !isReflective();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ if (isReflective()) {
+ return getSourceLifeline();
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Tests whether this a reflective message, i.e. both its source and target
+ * are in the context of the same lifeline.
+ *
+ * @return <code>true</code> if this message is reflective.
+ */
+ public boolean isReflective() {
+ Option<Lifeline> sourceLifeline = getSourceLifeline();
+ Option<Lifeline> targetLifeline = getTargetLifeline();
+ return sourceLifeline.some() && targetLifeline.some() && sourceLifeline.get() == targetLifeline.get();
+ }
+
+ /**
+ * Returns the lifeline in the context of which this message is sent.
+ *
+ * @return the lifeline in the context of which this message is sent.
+ */
+ public Option<Lifeline> getSourceLifeline() {
+ ISequenceNode sourceElement = getSourceElement();
+ if (sourceElement != null) {
+ return sourceElement.getLifeline();
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Returns the lifeline in the context of which this message is received.
+ *
+ * @return the lifeline in the context of which this message is received.
+ */
+ public Option<Lifeline> getTargetLifeline() {
+ ISequenceNode targetElement = getTargetElement();
+ if (targetElement != null) {
+ return targetElement.getLifeline();
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Returns the lifeline on "the other side" of the message, with respect to
+ * the specified lifeline. For reflective messages, this is the same as the
+ * local lifeline. The specified local lifeline <em>must</em> be either the
+ * source of target lifeline of this message. Otherwise the result is
+ * unspecified.
+ *
+ * @param local
+ * the lifeline to consider as "local", either the source or
+ * target lifeline of the message.
+ * @return the lifeline on "the other side" of the message, i.e. the the
+ * target lifeline is <code>local</code> it the source lifeline, and
+ * the source lifeline otherwise.
+ */
+ public Option<Lifeline> getRemoteLifeline(Lifeline local) {
+ Option<Lifeline> sourceLifeline = getSourceLifeline();
+ if (local == sourceLifeline.get()) {
+ return getTargetLifeline();
+ } else {
+ return sourceLifeline;
+ }
+ }
+
+ public boolean isCompoundMessage() {
+ return !Iterables.isEmpty(Iterables.filter(getDiagram().findEnds(this), CompoundEventEnd.class));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ Range range = getVerticalRange();
+
+ ISequenceNode srcElement = getSourceElement();
+ ISequenceNode tgtElement = getTargetElement();
+
+ Rectangle srcLogicalBounds = srcElement.getProperLogicalBounds().getCopy();
+ Rectangle tgtLogicalBounds = tgtElement.getProperLogicalBounds().getCopy();
+
+ int srcCenterX = srcLogicalBounds.getCenter().x;
+ int tgtCenterX = tgtLogicalBounds.getCenter().x;
+
+ int srcX = 0;
+ int tgtX = 0;
+ if (isReflective()) {
+ srcX = srcLogicalBounds.getRight().x;
+ tgtX = tgtLogicalBounds.getRight().x;
+ } else if (srcCenterX <= tgtCenterX) {
+ srcX = srcLogicalBounds.getRight().x;
+ tgtX = tgtLogicalBounds.getLeft().x;
+ } else {
+ srcX = srcLogicalBounds.getLeft().x;
+ tgtX = tgtLogicalBounds.getRight().x;
+ }
+
+ if (srcElement instanceof Lifeline) {
+ srcX = srcLogicalBounds.getCenter().x;
+ }
+
+ if (tgtElement instanceof Lifeline) {
+ tgtX = tgtLogicalBounds.getCenter().x;
+ }
+
+ return new Rectangle(srcX, range.getLowerBound(), tgtX - srcX, range.width());
+ }
+
+ /**
+ * Messages have no sub-events.
+ * <p>
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ISequenceEvent> getEventsToMoveWith() {
+ return getSubEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getParentEvent() {
+ ISequenceNode sourceElement = getSourceElement();
+ if (sourceElement instanceof ISequenceEvent) {
+ return (ISequenceEvent) sourceElement;
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getHierarchicalParentEvent() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getOccupiedRange() {
+ return new ISequenceEventQuery(this).getOccupiedRange();
+ }
+
+ /**
+ * Messages have no sub-events.
+ * <p>
+ * {@inheritDoc}
+ */
+ public Range getValidSubEventsRange() {
+ return Range.emptyRange();
+ }
+
+ /**
+ * Messages have no sub-events.
+ * <p>
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return false;
+ }
+
+ /**
+ * Messages have no sub-events.
+ * <p>
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Operand> getParentOperand() {
+ Option<Lifeline> sourceLifeline = getSourceLifeline();
+ Option<Operand> sourceParentOperand = Options.newNone();
+ if (sourceLifeline.some()) {
+ sourceParentOperand = sourceLifeline.get().getParentOperand(getVerticalRange());
+ }
+
+ Option<Lifeline> targetLifeline = getTargetLifeline();
+ Option<Operand> targetParentOperand = Options.newNone();
+ if (targetLifeline.some()) {
+ targetParentOperand = targetLifeline.get().getParentOperand(getVerticalRange());
+ }
+
+ boolean noOperand = !sourceParentOperand.some() && !targetParentOperand.some();
+ boolean lostEnd = sourceLifeline.some() && !targetLifeline.some() || !sourceLifeline.some() && targetLifeline.some();
+ boolean sameOperand = lostEnd || noOperand || sourceParentOperand.get().equals(targetParentOperand.get());
+ Preconditions.checkArgument(noOperand || sameOperand, "The source and target parent operand must be the same one or not existing.");
+
+ Option<Operand> parentOperand = sourceParentOperand;
+ if (!parentOperand.some()) {
+ parentOperand = targetParentOperand;
+ }
+
+ return parentOperand;
+ }
+
+ /**
+ * Check if the current message is reflexive and surrounds other events on
+ * the same lifeline.
+ *
+ * @return true if the current message is reflexive and surrounds other
+ * events on the same lifeline.
+ */
+ public boolean surroundsEventOnSameLifeline() {
+ return !getSurroundedSameLifelineEvents().isEmpty();
+ }
+
+ /**
+ * Get the surrounded reflexives message depth.
+ *
+ * @return the surrounded reflexives message depth.
+ */
+ public int getReflexiveMessageWidth() {
+ Collection<ISequenceEvent> events = getSurroundedSameLifelineEvents();
+ final Range range = getVerticalRange();
+ Predicate<ISequenceEvent> toConsider = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ boolean toConsider = range.includes(input.getVerticalRange());
+ if (input instanceof Message) {
+ toConsider = toConsider && ((Message) input).isReflective();
+ }
+ return toConsider;
+ }
+ };
+
+ List<ISequenceEvent> impactingEvents = Lists.newArrayList(Iterables.filter(events, toConsider));
+ Collections.sort(impactingEvents, Ordering.natural().onResultOf(Functions.compose(Range.lowerBoundFunction(), ISequenceEvent.VERTICAL_RANGE)));
+ int subMessagesMaxRight = 0;
+ for (Message msg : Iterables.filter(impactingEvents, Message.class)) {
+ int reflexiveMessageWidth = msg.getReflexiveMessageWidth();
+ int origin = msg.getSourceElement().getProperLogicalBounds().right();
+ origin = Math.max(origin, msg.getTargetElement().getProperLogicalBounds().right());
+ subMessagesMaxRight = Math.max(subMessagesMaxRight, origin + reflexiveMessageWidth);
+ }
+
+ int maxRight = 0;
+ for (AbstractNodeEvent node : Iterables.filter(impactingEvents, AbstractNodeEvent.class)) {
+ maxRight = Math.max(maxRight, node.getProperLogicalBounds().right());
+ }
+
+ int origin = getSourceElement().getProperLogicalBounds().right();
+ origin = Math.max(origin, getTargetElement().getProperLogicalBounds().right());
+
+ int width = LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_HORIZONTAL_GAP;
+ width = Math.max(width, maxRight - origin + LayoutConstants.MESSAGE_TO_SELF_HORIZONTAL_GAP);
+ width = Math.max(width, subMessagesMaxRight - origin + LayoutConstants.MESSAGE_TO_SELF_HORIZONTAL_GAP);
+
+ return width;
+ }
+
+ /**
+ * Get the surrounded events on the same lifeline.
+ *
+ * @return the surrounded events on the same lifeline.
+ */
+ public Collection<ISequenceEvent> getSurroundedSameLifelineEvents() {
+ Set<ISequenceEvent> englobedEvents = new LinkedHashSet<ISequenceEvent>();
+ if (isReflective()) {
+ Lifeline lifeline = getLifeline().get();
+ SequenceDiagram diagram = getDiagram();
+ EventEndsOrdering semanticOrdering = diagram.getSequenceDDiagram().getSemanticOrdering();
+ List<EventEnd> msgEnds = EventEndHelper.findEndsFromSemanticOrdering(this);
+ if (msgEnds.size() == 2) {
+ int start = semanticOrdering.getEventEnds().indexOf(msgEnds.get(0));
+ int end = semanticOrdering.getEventEnds().indexOf(msgEnds.get(1));
+ if (Math.abs(start - end) > 1) {
+ Collection<SingleEventEnd> sees = Sets.newHashSet();
+ Collection<ISequenceEvent> interEvents = Sets.newHashSet();
+
+ for (int i = start + 1; i < end; i++) {
+ EventEnd eventEnd = semanticOrdering.getEventEnds().get(i);
+ if (eventEnd instanceof SingleEventEnd) {
+ sees.add((SingleEventEnd) eventEnd);
+ } else if (eventEnd instanceof CompoundEventEnd) {
+ sees.addAll(((CompoundEventEnd) eventEnd).getEventEnds());
+ }
+ }
+
+ for (SingleEventEnd see : sees) {
+ ISequenceEvent perturbing = EventEndHelper.findISequenceEvent(see, diagram);
+ if (perturbing != null) {
+ interEvents.add(perturbing);
+ }
+ }
+
+ englobedEvents.addAll(getValidInterEvents(interEvents, lifeline));
+ }
+ }
+ }
+ return englobedEvents;
+ }
+
+ private Collection<? extends ISequenceEvent> getValidInterEvents(Collection<ISequenceEvent> interEvents, Lifeline lifeline) {
+ Set<ISequenceEvent> englobedEvents = new LinkedHashSet<ISequenceEvent>();
+ for (ISequenceEvent pertub : interEvents) {
+ if (pertub instanceof Message) {
+ Message msg = (Message) pertub;
+ Option<Lifeline> sourceLifeline = msg.getSourceLifeline();
+ Option<Lifeline> targetLifeline = msg.getTargetLifeline();
+ if (targetLifeline.some() && targetLifeline.get().equals(lifeline)) {
+ englobedEvents.add(pertub);
+ } else if (sourceLifeline.some() && sourceLifeline.get().equals(lifeline)) {
+ englobedEvents.add(pertub);
+ }
+ } else if (pertub instanceof CombinedFragment) {
+ CombinedFragment cf = (CombinedFragment) pertub;
+ Collection<Lifeline> coverage = cf.computeCoveredLifelines();
+ if (coverage.contains(lifeline)) {
+ englobedEvents.add(pertub);
+ }
+ } else {
+ Option<Lifeline> pLif = pertub.getLifeline();
+ if (pLif.some() && pLif.get().equals(lifeline)) {
+ englobedEvents.add(pertub);
+ }
+ }
+ }
+ return englobedEvents;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ObservationPoint.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ObservationPoint.java
new file mode 100644
index 0000000000..6e6daa8282
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/ObservationPoint.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+
+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.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+
+/**
+ * Represents the ObservationPoint marker which can appear to represent a
+ * EventEnd location.
+ *
+ * @author mporhel
+ */
+public class ObservationPoint extends AbstractSequenceNode {
+ /**
+ * The visual ID. Same as a standard node.
+ *
+ * see org.eclipse.sirius.diagram.internal.edit.parts.DNodeEditPart.
+ * VISUAL_ID
+ */
+ public static final int VISUAL_ID = 2001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * ObservationPoint.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getObservationPointMapping());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node which represents this ObservationPoint.
+ */
+ ObservationPoint(Node node) {
+ super(node);
+ Preconditions.checkArgument(ObservationPoint.notationPredicate().apply(node), "The node does not represent an observation point.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an
+ * ObservationPoint.
+ *
+ * @return a predicate to check whether a GMF View represents an
+ * ObservationPoint.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, ObservationPoint.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an ObservationPoint.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an ObservationPoint.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ return new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Look in its diagram'semantic ordering for the observed eventEnd: and
+ * event end whose semantic end is the observation point semantic target
+ * element.
+ *
+ * @return the observed EventEnd if valid.
+ */
+ public Option<EventEnd> getObservedEventEnd() {
+ Option<EObject> semanticTargetElement = getSemanticTargetElement();
+ if (semanticTargetElement.some()) {
+ for (EventEnd eventEnd : getDiagram().getSequenceDDiagram().getSemanticOrdering().getEventEnds()) {
+ if (eventEnd.getSemanticEnd() == semanticTargetElement.get()) {
+ return Options.newSome(eventEnd);
+ }
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Get the observed logical location (ie: it corresponds to the center of
+ * the logical bounds).
+ *
+ * @return the observed logical location.
+ */
+ public Point getObservedLogicalLocation() {
+ return getProperLogicalBounds().getCenter().getCopy();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Operand.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Operand.java
new file mode 100644
index 0000000000..ac085cd530
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/Operand.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+
+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.diagram.sequence.business.internal.layout.LayoutConstants;
+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.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.SubEventsHelper;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents an operand inside a combined fragment.
+ *
+ * @author pcdavid
+ */
+public class Operand extends AbstractSequenceNode implements ISequenceEvent {
+ /**
+ * The visual ID.
+ *
+ * @see DNodeContainer2EditPart.VISUAL_ID.
+ */
+ public static final int VISUAL_ID = 3008;
+
+ /**
+ * The visual ID of the compartment contained by the operand.
+ *
+ * see org.eclipse.sirius.diagram.internal.edit.parts.
+ * DNodeContainerViewNodeContainerCompartment2EditPart.VISUAL_ID
+ */
+ public static final int COMPARTMENT_VISUAL_ID = 7002;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents an
+ * execution.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getOperandMapping());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing the operand.
+ */
+ Operand(Node node) {
+ super(node);
+ Preconditions.checkArgument(Operand.notationPredicate().apply(node), "The node does not represent an operand.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an execution.
+ *
+ * @return a predicate to check whether a GMF View represents an execution.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, Operand.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents an combined
+ * fragment compartment.
+ *
+ * @return a predicate to check whether a GMF View represents an combined
+ * fragment compartment.
+ */
+ public static Predicate<View> compartmentNotationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), COMPARTMENT_VISUAL_ID, Operand.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents an execution.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * Operands are not associated to a particular lifeline.
+ * <p>
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle getProperLogicalBounds() {
+ Rectangle cfBounds = getCombinedFragment().getProperLogicalBounds();
+ if (getNotationNode().getLayoutConstraint() instanceof Bounds) {
+ Bounds bounds = (Bounds) getNotationNode().getLayoutConstraint();
+ return new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()).getTranslated(cfBounds.getLocation());
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getParentEvent() {
+ return getCombinedFragment();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ISequenceEvent getHierarchicalParentEvent() {
+ return getCombinedFragment();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return new SubEventsHelper(this).getSubEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ISequenceEvent> getEventsToMoveWith() {
+ return getSubEvents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getVerticalRange() {
+ // Rectangle logicalBounds = getProperLogicalBounds();
+ // return new Range(logicalBounds.y, logicalBounds.bottom());
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLogicallyInstantaneous() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * Finds the parent Combined fragment.
+ *
+ * @return the parent Combined fragment.
+ */
+ public CombinedFragment getCombinedFragment() {
+ EObject viewContainer = this.view.eContainer();
+ if (viewContainer instanceof View) {
+ View parentView = (View) viewContainer;
+ Option<CombinedFragment> parentElement = ISequenceElementAccessor.getCombinedFragment(parentView);
+ // The parent should be the compartment of the Combined Fragment
+ if (parentElement.some()) {
+ return parentElement.get();
+ } else {
+ // The grand parent should be the Combined Fragment we are
+ // looking for
+ View grandParentView = (View) viewContainer.eContainer();
+ Option<CombinedFragment> grandparentElement = ISequenceElementAccessor.getCombinedFragment(grandParentView);
+ if (grandparentElement.some()) {
+ return grandparentElement.get();
+ }
+ }
+ }
+ throw new RuntimeException("Invalid context for operand " + this);
+ }
+
+ /**
+ * Finds the index of this operand among the parent combined fragment.
+ *
+ * @return the index of this operand among the parent combined fragment.
+ */
+ public int getIndex() {
+ CombinedFragment parentCombinedFragment = getCombinedFragment();
+ return parentCombinedFragment.getIndexOfOperand(this);
+ }
+
+ /**
+ * Check if this operand is the last in the parent {@link CombinedFragment}.
+ *
+ * @return if this operand is the last in the parent
+ * {@link CombinedFragment}.
+ */
+ public boolean isLastOperand() {
+ return getIndex() == getCombinedFragment().getOperands().size() - 1;
+ }
+
+ /**
+ * Check if this operand is the first in the parent {@link CombinedFragment}
+ * .
+ *
+ * @return if this operand is the first in the parent
+ * {@link CombinedFragment}.
+ */
+ public boolean isFirstOperand() {
+ return getIndex() == 0;
+ }
+
+ /**
+ * Finds the following operand.
+ *
+ * @return the following operand if existing, Options.newNone() otherwise
+ */
+ public Option<Operand> getFollowingOperand() {
+ CombinedFragment combinedFragment = getCombinedFragment();
+ return combinedFragment.getOperand(combinedFragment.getIndexOfOperand(this) + 1);
+ }
+
+ /**
+ * Finds the previous operand.
+ *
+ * @return the previous operand if existing, Options.newNone() otherwise
+ */
+ public Option<Operand> getPreviousOperand() {
+ CombinedFragment combinedFragment = getCombinedFragment();
+ return combinedFragment.getOperand(combinedFragment.getIndexOfOperand(this) - 1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return new SubEventsHelper(this).canChildOccupy(child, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return new SubEventsHelper(this).canChildOccupy(child, range, eventsToIgnore, lifelines);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getOccupiedRange() {
+ return new ISequenceEventQuery(this).getOccupiedRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getValidSubEventsRange() {
+ return getVerticalRange().shrinked(LayoutConstants.EXECUTION_CHILDREN_MARGIN);
+ }
+
+ /**
+ * Get the covered lifelines.
+ *
+ * @return the covered lifelines.
+ */
+ public Collection<Lifeline> computeCoveredLifelines() {
+ return getCombinedFragment().computeCoveredLifelines();
+ }
+
+ /**
+ * Returns the last event end (in semantic order) which is contained inside
+ * this operand, excluding the operand's finishing end. If the operand is
+ * empty, this is the starting end of the operand itself.
+ *
+ * @return the last event end which is contained inside this operand.
+ */
+ public EventEnd getLastContainedEventEnd() {
+ List<ISequenceEvent> subEvents = getSubEvents();
+ if (subEvents.isEmpty()) {
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(this);
+ assert !ends.isEmpty();
+ return ends.get(0);
+ } else {
+ ISequenceEvent lastEvent = subEvents.get(subEvents.size() - 1);
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(lastEvent);
+ assert ends.size() == 2;
+ return ends.get(1);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Operand> getParentOperand() {
+ return getCombinedFragment().getParentOperand();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/SequenceDiagram.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/SequenceDiagram.java
new file mode 100644
index 0000000000..9497c4a717
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/SequenceDiagram.java
@@ -0,0 +1,463 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+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 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 com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.AllContents;
+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.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents a sequence diagram. This is the root of all sequence elements.
+ *
+ * @author mporhel, pcdavid
+ */
+public class SequenceDiagram extends AbstractSequenceElement {
+
+ private static final String INTERNAL_ERROR = "Internal error.";
+
+ /**
+ * Predicate to check whether a GMF View represents a sequence diagram.
+ */
+ private static enum NotationPredicate implements Predicate<View> {
+ INSTANCE;
+
+ public boolean apply(View input) {
+ if (input instanceof Diagram) {
+ EObject element = input.getElement();
+ return element instanceof DDiagram && SequenceDiagram.viewpointElementPredicate().apply((DDiagram) element);
+ } else {
+ return false;
+ }
+ }
+
+ }
+
+ /**
+ * Predicate to check whether a Sirius DDiagram represents a sequence
+ * diagram.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagram> {
+ INSTANCE;
+
+ public boolean apply(DDiagram input) {
+ if (input == null) {
+ return false;
+ } else {
+ EClass sdDescClass = DescriptionPackage.eINSTANCE.getSequenceDiagramDescription();
+ return input instanceof SequenceDDiagram && sdDescClass.isInstance(input.getDescription());
+ }
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the GMF Diagram representing this sequence diagram.
+ */
+ SequenceDiagram(Diagram diagram) {
+ super(diagram);
+ Preconditions.checkArgument(SequenceDiagram.notationPredicate().apply(diagram), "The diagram does not represent a sequence diagram.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents a sequence
+ * diagram.
+ *
+ * @return a predicate to check whether a GMF View represents a sequence
+ * diagram.
+ */
+ public static Predicate<View> notationPredicate() {
+ return NotationPredicate.INSTANCE;
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagram represents a
+ * sequence diagram.
+ *
+ * @return a predicate to check whether a Sirius DDiagram represents a
+ * sequence diagram.
+ */
+ public static Predicate<DDiagram> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ public Diagram getNotationDiagram() {
+ return (Diagram) view;
+ }
+
+ public SequenceDDiagram getSequenceDDiagram() {
+ return (SequenceDDiagram) view.getElement();
+ }
+
+ /**
+ * Finds all the lifelines in this diagram which are at least partially
+ * covered by the specified rectangular area.
+ *
+ * @param area
+ * the rectangular area to check for lifelines (in logical
+ * coordinates).
+ * @return all the lifelines in this diagram which are at least partially
+ * covered by the area.
+ */
+ public Set<Lifeline> getGraphicallyCoveredLifelines(final Rectangle area) {
+ List<Lifeline> result = Lists.newArrayList();
+ Iterables.addAll(result, Iterables.filter(getAllLifelines(), new Predicate<Lifeline>() {
+ public boolean apply(Lifeline input) {
+ return input.getProperLogicalBounds().intersects(area) && input.getVerticalRange().includes(area.getTop().y);
+ }
+ }));
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * .
+ *
+ * @return .
+ */
+ public List<InstanceRole> getSortedInstanceRole() {
+ Function<InstanceRole, Integer> xLocation = new Function<InstanceRole, Integer>() {
+ public Integer apply(InstanceRole from) {
+ Rectangle bounds = from.getBounds();
+ return bounds.x;
+ }
+ };
+
+ List<InstanceRole> allInstanceRoles = Lists.newArrayList(getAllInstanceRoles());
+ Collections.sort(allInstanceRoles, Ordering.natural().onResultOf(xLocation));
+ return allInstanceRoles;
+ }
+
+ /**
+ * .
+ *
+ * @return .
+ */
+ public Collection<InstanceRole> getAllInstanceRoles() {
+ Collection<InstanceRole> result = Lists.newArrayList();
+ for (View child : Iterables.filter(getNotationView().getChildren(), View.class)) {
+ if (InstanceRole.notationPredicate().apply(child)) {
+ Option<InstanceRole> instanceRole = ISequenceElementAccessor.getInstanceRole(child);
+ if (instanceRole.some()) {
+ result.add(instanceRole.get());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * .
+ *
+ * @return .
+ */
+ public List<Lifeline> getAllLifelines() {
+ Collection<InstanceRole> allInstanceRoles = getAllInstanceRoles();
+ Function<ISequenceNode, Lifeline> lifelineFunction = new Function<ISequenceNode, Lifeline>() {
+ public Lifeline apply(ISequenceNode from) {
+ return from.getLifeline().get();
+ }
+ };
+ List<Lifeline> result = Lists.newArrayList(Iterables.transform(allInstanceRoles, lifelineFunction));
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return result;
+ }
+
+ /**
+ * Returns all the {@link Node}s in the specified diagram which represent an
+ * ObservationPoint.
+ *
+ * @return the Nodes inside this diagram which represent sequence
+ * ObservationPoint. An empty iterator is returned if the diagram is
+ * not a sequence diagram.
+ */
+ public Collection<ObservationPoint> getAllObservationPoints() {
+ Collection<ObservationPoint> result = Lists.newArrayList();
+ for (View child : Iterables.filter(getNotationView().getChildren(), View.class)) {
+ if (ObservationPoint.notationPredicate().apply(child)) {
+ Option<ObservationPoint> obsPoint = ISequenceElementAccessor.getObservationPoint(child);
+ if (obsPoint.some()) {
+ result.add(obsPoint.get());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns all the {@link Node}s in the specified diagram which represent a
+ * lost sequence message end.
+ *
+ * @return the Nodes inside this diagram which represent lost sequence
+ * messages end. An empty iterator is returned if the diagram is not
+ * a sequence diagram.
+ */
+ public Collection<LostMessageEnd> getAllLostMessageEnds() {
+ Collection<LostMessageEnd> result = Lists.newArrayList();
+ for (View child : Iterables.filter(getNotationView().getChildren(), View.class)) {
+ if (LostMessageEnd.notationPredicate().apply(child)) {
+ Option<LostMessageEnd> lostMessageEnd = ISequenceElementAccessor.getLostMessageEnd(child);
+ if (lostMessageEnd.some()) {
+ result.add(lostMessageEnd.get());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns all the {@link Edge}s in the specified diagram which represent a
+ * sequence message of any kind.
+ *
+ * @return the Edges inside this diagram which represent sequence messages.
+ * An empty iterator is returned if the diagram is not a sequence
+ * diagram.
+ */
+ public Set<Message> getAllMessages() {
+ List<Message> result = Lists.newArrayList();
+ for (Edge edge : Iterables.filter(Iterables.filter(getNotationDiagram().getEdges(), Edge.class), Message.notationPredicate())) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(edge);
+ assert message.some() : INTERNAL_ERROR;
+ result.add(message.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all AbstractNodeEvent in the given diagram.
+ *
+ * @return all AbstractNodeEvent on the given diagram.
+ */
+ public Set<AbstractNodeEvent> getAllAbstractNodeEvents() {
+ List<AbstractNodeEvent> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(AllContents.of(getNotationDiagram()), Node.class), AbstractNodeEvent.notationPredicate())) {
+ Option<AbstractNodeEvent> exec = ISequenceElementAccessor.getAbstractNodeEvent(node);
+ assert exec.some() : INTERNAL_ERROR;
+ result.add(exec.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all executions in the given diagram.
+ *
+ * @return all executions on the given diagram.
+ */
+ public Set<Execution> getAllExecutions() {
+ List<Execution> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(AllContents.of(getNotationDiagram()), Node.class), Execution.notationPredicate())) {
+ Option<Execution> exec = ISequenceElementAccessor.getExecution(node);
+ assert exec.some() : INTERNAL_ERROR;
+ result.add(exec.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all executions in the given diagram.
+ *
+ * @return all executions on the given diagram.
+ */
+ public Set<State> getAllStates() {
+ List<State> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(AllContents.of(getNotationDiagram()), Node.class), State.notationPredicate())) {
+ Option<State> exec = ISequenceElementAccessor.getState(node);
+ assert exec.some() : INTERNAL_ERROR;
+ result.add(exec.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all frames in the given diagram.
+ *
+ * @return all frames on the given diagram.
+ */
+ public Collection<AbstractFrame> getAllFrames() {
+ List<AbstractFrame> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(getNotationDiagram().getChildren(), Node.class), AbstractFrame.notationPredicate())) {
+ Option<ISequenceEvent> exec = ISequenceElementAccessor.getISequenceEvent(node);
+ assert exec.some() : INTERNAL_ERROR;
+ if (exec.get() instanceof AbstractFrame) {
+ result.add((AbstractFrame) exec.get());
+ }
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all interaction uses in the given diagram.
+ *
+ * @return all interaction uses on the given diagram.
+ */
+ public Set<InteractionUse> getAllInteractionUses() {
+ List<InteractionUse> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(getNotationDiagram().getChildren(), Node.class), InteractionUse.notationPredicate())) {
+ Option<InteractionUse> exec = ISequenceElementAccessor.getInteractionUse(node);
+ assert exec.some() : INTERNAL_ERROR;
+ result.add(exec.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all combined fragments in the given diagram.
+ *
+ * @return all combined fragments on the given diagram.
+ */
+ public Set<CombinedFragment> getAllCombinedFragments() {
+ List<CombinedFragment> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(getNotationDiagram().getChildren(), Node.class), CombinedFragment.notationPredicate())) {
+ Option<CombinedFragment> exec = ISequenceElementAccessor.getCombinedFragment(node);
+ assert exec.some() : INTERNAL_ERROR;
+ result.add(exec.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all operands in the given diagram.
+ *
+ * @return all operands on the given diagram.
+ */
+ public Set<Operand> getAllOperands() {
+ List<Operand> result = Lists.newArrayList();
+ for (Node node : Iterables.filter(Iterables.filter(AllContents.of(getNotationDiagram()), Node.class), Operand.notationPredicate())) {
+ Option<Operand> exec = ISequenceElementAccessor.getOperand(node);
+ assert exec.some() : INTERNAL_ERROR;
+ result.add(exec.get());
+ }
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all endOfLifes in the given diagram.
+ *
+ * @return all endOfLifes on the given diagram.
+ */
+ public Set<EndOfLife> getAllEndOfLifes() {
+ Set<EndOfLife> allEndOfLifes = new HashSet<EndOfLife>();
+ for (Lifeline lifeline : getAllLifelines()) {
+ if (lifeline.getEndOfLife().some()) {
+ allEndOfLifes.add(lifeline.getEndOfLife().get());
+ }
+ }
+ return allEndOfLifes;
+ }
+
+ /**
+ * Returns all sequence events in the given diagram. The result is ordered
+ * regarding the lower bound ordering.
+ *
+ * @return all sequence events on the given diagram.
+ */
+ public Set<ISequenceEvent> getAllOrderedDelimitedSequenceEvents() {
+ List<ISequenceEvent> result = Lists.newArrayList();
+ Iterables.addAll(result, getAllDelimitedSequenceEvents());
+
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return Sets.newLinkedHashSet(result);
+ }
+
+ /**
+ * Returns all sequence events in the given diagram. The result is not
+ * ordered and will be computed on iteration.
+ *
+ * @return all sequence events on the given diagram.
+ */
+ public Iterable<? extends ISequenceEvent> getAllDelimitedSequenceEvents() {
+ Function<View, ? extends ISequenceEvent> getISE = new Function<View, ISequenceEvent>() {
+ public ISequenceEvent apply(View from) {
+ Option<ISequenceEvent> ise = ISequenceElementAccessor.getISequenceEvent(from);
+ assert ise.some() : INTERNAL_ERROR;
+ return ise.get();
+ }
+ };
+ return Iterables.transform(Iterables.filter(Iterables.filter(AllContents.of(getNotationDiagram()), View.class), ISequenceEvent.ISEQUENCEEVENT_NOTATION_PREDICATE), getISE);
+ }
+
+ /**
+ * Finds and returns the EventEnds corresponding to the given part.
+ *
+ * @param event
+ * current event
+ * @return the EventEnds corresponding to the given part
+ */
+ public List<EventEnd> findEnds(ISequenceEvent event) {
+ List<EventEnd> ends = Lists.newArrayList();
+ EObject seqDiag = getNotationDiagram().getElement();
+ Option<EObject> semanticEvent = event.getSemanticTargetElement();
+ if (seqDiag instanceof SequenceDDiagram && semanticEvent.some()) {
+ for (EventEnd ee : ((SequenceDDiagram) seqDiag).getGraphicalOrdering().getEventEnds()) {
+ if (EventEndHelper.getSemanticEvents(ee).contains(semanticEvent.get())) {
+ ends.add(ee);
+ }
+ }
+ }
+ return ends;
+ }
+
+ /**
+ * Diagram are not associated to a particular lifeline.
+ * <p>
+ * {@inheritDoc}
+ */
+ public Option<Lifeline> getLifeline() {
+ return Options.newNone();
+ }
+
+ /**
+ * The diagram itself has no significant bounds.
+ *
+ * @return the bounds of the diagram.
+ */
+ public Rectangle getProperLogicalBounds() {
+ return new Rectangle(0, 0, 0, 0);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/State.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/State.java
new file mode 100644
index 0000000000..2c01d0ba40
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/State.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.ParentOperandFinder;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.RangeSetter;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.NotationPredicate;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Represents a state on a lifeline or an execution.
+ *
+ * @author smonnier
+ */
+public class State extends AbstractNodeEvent {
+
+ /**
+ * The visual ID. Same as a normal bordered node.
+ *
+ * @see DNode2EditPart.VISUAL_ID
+ */
+ public static final int VISUAL_ID = 3001;
+
+ /**
+ * Predicate to check whether a Sirius DDiagramElement represents a
+ * state.
+ */
+ private static enum SiriusElementPredicate implements Predicate<DDiagramElement> {
+ INSTANCE;
+
+ public boolean apply(DDiagramElement input) {
+ return AbstractSequenceElement.isSequenceDiagramElement(input, DescriptionPackage.eINSTANCE.getStateMapping())
+ && !InstanceRole.viewpointElementPredicate().apply((DDiagramElement) input.eContainer());
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the GMF Node representing this state.
+ */
+ State(Node node) {
+ super(node);
+ Preconditions.checkArgument(State.notationPredicate().apply(node), "The node does not represent an state.");
+ }
+
+ /**
+ * Returns a predicate to check whether a GMF View represents a state.
+ *
+ * @return a predicate to check whether a GMF View represents a state.
+ */
+ public static Predicate<View> notationPredicate() {
+ return new NotationPredicate(NotationPackage.eINSTANCE.getNode(), VISUAL_ID, State.viewpointElementPredicate());
+ }
+
+ /**
+ * Returns a predicate to check whether a Sirius DDiagramElement
+ * represents a state.
+ *
+ * @return a predicate to check whether a Sirius DDiagramElement
+ * represents a state.
+ */
+ public static Predicate<DDiagramElement> viewpointElementPredicate() {
+ return SiriusElementPredicate.INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<ISequenceEvent> getEventsToMoveWith() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISequenceEvent getHierarchicalParentEvent() {
+ EObject viewContainer = this.view.eContainer();
+ if (viewContainer instanceof View) {
+ View parentView = (View) viewContainer;
+ Option<ISequenceEvent> parentElement = ISequenceElementAccessor.getISequenceEvent(parentView);
+ if (parentElement.some()) {
+ return parentElement.get();
+ }
+ }
+ throw new RuntimeException("Invalid context for state " + this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getOccupiedRange() {
+ return Range.emptyRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISequenceEvent getParentEvent() {
+ ISequenceEvent parent = getHierarchicalParentEvent();
+
+ List<ISequenceEvent> potentialSiblings = parent.getSubEvents();
+ if (!potentialSiblings.contains(this)) {
+ // look for parentOperand
+ parent = getParentOperand().get();
+ }
+ return parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Operand> getParentOperand() {
+ return new ParentOperandFinder(this).getParentOperand();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Range getValidSubEventsRange() {
+ return Range.emptyRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Range getVerticalRange() {
+ return new SequenceNodeQuery(getNotationNode()).getVerticalRange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLogicallyInstantaneous() {
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(this);
+ return ends.size() == 1 && EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(ends.iterator().next());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setVerticalRange(Range range) throws IllegalStateException {
+ RangeSetter.setVerticalRange(this, range);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Option<Lifeline> getLifeline() {
+ return getParentLifeline();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Message> getLinkedMessages() {
+ return Collections.emptyList();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/package-info.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/package-info.java
new file mode 100644
index 0000000000..310f17a23d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/elements/package-info.java
@@ -0,0 +1,12 @@
+/*******************************************************************************
+ * 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.business.internal.elements;
+
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceLayout.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceLayout.java
new file mode 100644
index 0000000000..6ef85337cd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceLayout.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * 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.business.internal.layout;
+
+import java.util.Map;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+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.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.business.internal.query.ISequenceElementQuery;
+
+/**
+ * Computes the appropriate graphical locations of sequence events and lifelines
+ * on a sequence diagram to reflect the semantic order.
+ *
+ * @param <S>
+ * the layouted element type.
+ *
+ * @param <T>
+ * the layout data type.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractSequenceLayout<S, T> {
+
+ /**
+ * The diagram to layout.
+ */
+ protected final SequenceDiagram sequenceDiagram;
+
+ /**
+ * A map to register old layout data.
+ */
+ protected final Map<ISequenceElement, T> oldLayoutData;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram to layout.
+ */
+ public AbstractSequenceLayout(SequenceDiagram sequenceDiagram) {
+ this.sequenceDiagram = sequenceDiagram;
+
+ this.oldLayoutData = Maps.newHashMap();
+ }
+
+ /**
+ * Compute and apply a specific layout. Should be use in a
+ * {@link org.eclipse.emf.transaction.RecordingCommand}.
+ *
+ * @param pack
+ * pack the space between instance roles.
+ *
+ * @return true if a layout was applied
+ */
+ public final boolean layout(boolean pack) {
+ // initialisation
+ init(pack);
+
+ // vertical range computation
+ Map<? extends S, T> finalRanges = computeLayout(pack);
+
+ // Apply computed ranges
+ boolean applied = applyComputedLayout(finalRanges, pack);
+
+ dispose();
+
+ return applied;
+
+ }
+
+ /**
+ * Init the needed context for layout computation.
+ *
+ * @param pack
+ * pack the diagram
+ */
+ protected abstract void init(boolean pack);
+
+ /**
+ * Get old layout data before layout application.
+ *
+ * @param ise
+ * the requested sequence element.
+ * @return the old layout data.
+ */
+ protected abstract T getOldLayoutData(S ise);
+
+ /**
+ * Computes the absolute vertical (Y) location for all the messages in the
+ * sequence diagram.
+ *
+ * @param pack
+ * pack the diagram
+ * @return a map associating each message edit part to the new absolute
+ * vertical location it should have.
+ */
+ protected abstract Map<? extends S, T> computeLayout(boolean pack);
+
+ /**
+ * Apply the computed layout.
+ *
+ * @param finalRanges
+ * a map associating each message edit part to the new absolute
+ * vertical location it should have.
+ * @param pack
+ * pack the diagram
+ *
+ * @return true if a layout was applied
+ */
+ protected abstract boolean applyComputedLayout(Map<? extends S, T> finalRanges, boolean pack);
+
+ /**
+ * Dispose the layout context after layout application.
+ */
+ protected void dispose() {
+ oldLayoutData.clear();
+ }
+
+ /**
+ * Return the non-explicitely created lifelines.
+ *
+ * @return the non-explicitely created lifelines.
+ */
+ protected Iterable<Lifeline> getLifeLinesWithoutCreation() {
+ Predicate<Lifeline> isMainLifeline = new Predicate<Lifeline>() {
+ public boolean apply(Lifeline input) {
+ boolean main = true;
+ InstanceRole instanceRole = input.getInstanceRole();
+ if (instanceRole != null) {
+ main = !instanceRole.isExplicitlyCreated();
+ }
+ return main;
+ }
+ };
+ return Iterables.filter(sequenceDiagram.getAllLifelines(), isMainLifeline);
+ }
+
+ /**
+ * Return the non-explicitely destructed lifelines.
+ *
+ * @return the non-explicitely destructed lifelines.
+ */
+ protected Iterable<Lifeline> getLifeLinesWithoutDestruction() {
+ Predicate<Lifeline> isLifelineWithoutDestruction = new Predicate<Lifeline>() {
+ public boolean apply(Lifeline input) {
+ boolean result = true;
+ // filter lifeline with endOfLife
+ Option<EndOfLife> endOfLife = input.getEndOfLife();
+ if (endOfLife.some()) {
+ result = !endOfLife.get().isExplicitelyDestroyed();
+ }
+ return result;
+ }
+ };
+ return Iterables.filter(sequenceDiagram.getAllLifelines(), isLifelineWithoutDestruction);
+ }
+
+ /**
+ * Check if the current lost end has been created from a tool application.
+ * Tool creation flags will be erased after the first layout.
+ *
+ * @param lostEnd
+ * the current end.
+ * @return true if the end was created by a tool.
+ */
+ public static boolean createdFromTool(LostMessageEnd lostEnd) {
+ boolean toolCreated = false;
+ ISequenceElementQuery query = new ISequenceElementQuery(lostEnd);
+ if (query.hasAbsoluteBoundsFlag() && query.getFlaggedAbsoluteBounds().x == LayoutConstants.TOOL_CREATION_FLAG_FROM_SEMANTIC.x) {
+ toolCreated = true;
+ }
+ return toolCreated;
+ }
+
+ /**
+ * Check if the current lost end has been created from a tool application.
+ * Tool creation flags will be erased after the first layout.
+ *
+ * @param lostEnd
+ * the current end.
+ * @return true if the end was created by a tool.
+ */
+ public static boolean createdFromExternalChange(LostMessageEnd lostEnd) {
+ boolean externalCreation = false;
+ Option<Message> message = lostEnd.getMessage();
+ ISequenceElementQuery query = new ISequenceElementQuery(lostEnd);
+ if (query.hasAbsoluteBoundsFlag() && query.getFlaggedAbsoluteBounds().x == LayoutConstants.EXTERNAL_CHANGE_FLAG.x) {
+ externalCreation = true;
+ } else if (message.some()) {
+ query = new ISequenceElementQuery(message.get());
+ externalCreation = query.hasAbsoluteBoundsFlag() && query.getFlaggedAbsoluteBounds().x == LayoutConstants.EXTERNAL_CHANGE_FLAG.x;
+ }
+ return externalCreation;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceOrderingLayout.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceOrderingLayout.java
new file mode 100644
index 0000000000..85561687d0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/AbstractSequenceOrderingLayout.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * 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.business.internal.layout;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import com.google.common.base.Function;
+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.SequenceDiagram;
+
+/**
+ * Computes the appropriate graphical locations of sequence events and lifelines
+ * on a sequence diagram to reflect the semantic order.
+ *
+ * @param <S>
+ * the layouted element type.
+ *
+ * @param <T>
+ * the layout data type.
+ *
+ * @param <U>
+ * the ordering type.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractSequenceOrderingLayout<S, T, U> extends AbstractSequenceLayout<S, T> {
+
+ /**
+ * The semantic ordering.
+ */
+ protected final List<U> semanticOrdering;
+
+ /**
+ * The graphical ordering.
+ */
+ protected final List<U> graphicalOrdering;
+
+ /**
+ * Semantic flagged ordering elements.
+ */
+ protected final List<U> flaggedEnds;
+
+ /**
+ * Old flagged absolute bounds.
+ */
+ protected final Map<S, Rectangle> oldFlaggedLayoutData;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram to layout.
+ */
+ public AbstractSequenceOrderingLayout(SequenceDiagram sequenceDiagram) {
+ super(sequenceDiagram);
+
+ this.semanticOrdering = Lists.newArrayList();
+ this.graphicalOrdering = Lists.newArrayList();
+ this.flaggedEnds = Lists.newArrayList();
+ this.oldFlaggedLayoutData = Maps.newHashMap();
+ }
+
+ /**
+ * Dispose the layout context after layout application.
+ */
+ protected void dispose() {
+ semanticOrdering.clear();
+ graphicalOrdering.clear();
+ flaggedEnds.clear();
+ oldFlaggedLayoutData.clear();
+ super.dispose();
+ }
+
+ /**
+ *
+ * Look in the semantic, graphical and flaggedEnds orderings to retrieve the
+ * safest predecessor and try to keep a stable delta regarding it.
+ *
+ * @param currentPos
+ * the current position (x or y)
+ * @param element
+ * the current ordering element
+ * @param alreadyComputedLocations
+ * the already computed locations
+ * @return the delta stable position.
+ */
+ protected int getDeltaStablePosition(final int currentPos, final U element, Map<? extends U, Integer> alreadyComputedLocations) {
+ int deltaStablePos = currentPos;
+ int semanticIndex = semanticOrdering.indexOf(element);
+ int graphicalIndex = graphicalOrdering.indexOf(element);
+ int flaggedIndex = flaggedEnds.indexOf(element);
+
+ if (flaggedIndex != -1 && semanticIndex != 0 && graphicalIndex != -1) {
+ List<U> semanticPredecessors = Lists.newArrayList(semanticOrdering.subList(0, semanticIndex));
+ List<U> graphicalPredecessors = Lists.newArrayList(graphicalOrdering.subList(0, graphicalIndex));
+ List<U> flaggedPredecessors = Lists.newArrayList(flaggedEnds.subList(0, flaggedIndex));
+
+ // Intersection
+ semanticPredecessors.retainAll(flaggedEnds);
+ graphicalPredecessors.retainAll(flaggedEnds);
+ flaggedPredecessors.retainAll(semanticPredecessors);
+
+ // Which is the safer position ?
+ Function<U, Integer> oldPosition = getOldPosition();
+ U flaggedPred = null;
+
+ if (Iterables.elementsEqual(semanticPredecessors, graphicalPredecessors) && !graphicalPredecessors.isEmpty()) {
+ flaggedPred = graphicalPredecessors.get(graphicalPredecessors.size() - 1);
+ } else {
+ // Desynchronisation -> flagged position
+ oldPosition = getOldFlaggedPosition();
+
+ // Look for the last semantic predecessor with same index in
+ // semantic and flagged lists.
+ U potentialSafePred = null;
+ for (int i = 0; i < flaggedPredecessors.size(); i++) {
+ U semPot = semanticPredecessors.get(i);
+ U flaggedPot = flaggedPredecessors.get(i);
+ if (semPot != null && semPot.equals(flaggedPot)) {
+ potentialSafePred = semPot;
+ }
+ }
+
+ if (potentialSafePred != null) {
+ flaggedPred = potentialSafePred;
+ }
+ }
+
+ if (flaggedPred != null) {
+ Integer predY = oldPosition.apply(flaggedPred);
+ Integer flaggedY = oldPosition.apply(element);
+ int delta = flaggedY - predY;
+ if (delta >= 0) {
+ deltaStablePos = alreadyComputedLocations.get(flaggedPred) + delta;
+ }
+ }
+ }
+ return deltaStablePos;
+ }
+
+ /**
+ * A function to retrieve the old positions.
+ *
+ * @return the function.
+ */
+ protected abstract Function<U, Integer> getOldPosition();
+
+ /**
+ * A function to retrieve the old flagged positions.
+ *
+ * @return the function.
+ */
+ protected abstract Function<U, Integer> getOldFlaggedPosition();
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/EventEndToPositionFunction.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/EventEndToPositionFunction.java
new file mode 100644
index 0000000000..0f77634cb8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/EventEndToPositionFunction.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * 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.business.internal.layout;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import com.google.common.base.Function;
+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 org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagramElement;
+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.ISequenceEvent;
+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.ISequenceElementQuery;
+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.util.Range;
+
+/**
+ * Function to compute position of and EventEnd.
+ *
+ * @author pcmporhel
+ */
+public class EventEndToPositionFunction implements Function<EventEnd, Integer> {
+
+ private final Function<EventEnd, Collection<ISequenceEvent>> eventEndToSequenceEvents;
+
+ private final Function<ISequenceEvent, Option<Range>> ranges;
+
+ /**
+ * Constructor.
+ *
+ * @param eventEndToSequenceEvents
+ * function to get sequence event linked to the given event end.
+ * @param ranges
+ * ranges of sequence events.
+ */
+ public EventEndToPositionFunction(Function<EventEnd, Collection<ISequenceEvent>> eventEndToSequenceEvents, Function<ISequenceEvent, Option<Range>> ranges) {
+ this.eventEndToSequenceEvents = eventEndToSequenceEvents;
+ this.ranges = ranges;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Integer apply(EventEnd from) {
+ return getOldPosition(from, eventEndToSequenceEvents.apply(from));
+ }
+
+ private Integer getOldPosition(EventEnd end, Collection<ISequenceEvent> ises) {
+ SingleEventEnd see = null;
+ ISequenceEvent ise = null;
+ if (end instanceof SingleEventEnd && !ises.isEmpty()) {
+ see = (SingleEventEnd) end;
+ ise = ises.iterator().next();
+ } else if (end instanceof CompoundEventEnd && !ises.isEmpty()) {
+ CompoundEventEnd cee = (CompoundEventEnd) end;
+ if (EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(cee)) {
+ ise = getSafeEvent(ises);
+ } else {
+ ise = getSafeEvent(ises);
+ see = ise == null ? null : EventEndHelper.getSingleEventEnd(end, ((DDiagramElement) ise.getNotationView().getElement()).getTarget());
+ }
+ }
+ return getOldPositionFromRange(see, ise);
+ }
+
+ private ISequenceEvent getSafeEvent(Collection<ISequenceEvent> ises) {
+ ISequenceEvent ise = null;
+ Predicate<Object> safe = Predicates.or(Predicates.instanceOf(AbstractNodeEvent.class), Predicates.instanceOf(AbstractFrame.class));
+ Collection<? extends ISequenceEvent> safeEvents = Lists.newArrayList(Iterables.filter(ises, safe));
+
+ if (!safeEvents.isEmpty()) {
+ ise = safeEvents.iterator().next();
+ } else if (Iterables.size(Iterables.filter(ises, Operand.class)) == 2) {
+ ise = getSafeOperandEnd(ises);
+ } else {
+ ise = ises.iterator().next();
+ }
+ return ise;
+ }
+
+ private ISequenceEvent getSafeOperandEnd(Collection<ISequenceEvent> ises) {
+ ISequenceEvent ise = null;
+
+ Iterator<ISequenceEvent> iterator = ises.iterator();
+ ISequenceEvent pot1 = iterator.next();
+ ISequenceEvent pot2 = iterator.next();
+
+ if (new ISequenceElementQuery(pot1).hasAbsoluteBoundsFlag()) {
+ ise = pot1;
+ } else if (new ISequenceElementQuery(pot2).hasAbsoluteBoundsFlag()) {
+ ise = pot2;
+ }
+ return ise;
+ }
+
+ /**
+ * Get the old position of the corresponding event end, regarding the given
+ * event old range. event.
+ *
+ * @param see
+ * event end
+ * @param ise
+ * corresponding event
+ * @return old position
+ */
+ protected Integer getOldPositionFromRange(SingleEventEnd see, ISequenceEvent ise) {
+ Integer oldPosition = 0;
+ Option<Range> oldRange = ranges.apply(ise);
+
+ if (ise != null && oldRange.some()) {
+ if (see != null) {
+ oldPosition = see.isStart() ? oldRange.get().getLowerBound() : oldRange.get().getUpperBound();
+ } else if (see == null && ise.isLogicallyInstantaneous()) {
+ oldPosition = oldRange.get().middleValue();
+ }
+ }
+ return oldPosition;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/LayoutConstants.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/LayoutConstants.java
new file mode 100644
index 0000000000..347faa8070
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/LayoutConstants.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * 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.business.internal.layout;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * 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 pcdavid, smonnier, mporhel, edugueperoux
+ */
+public final class LayoutConstants {
+
+ /**
+ * This should be LayoutUtils.SCALE, but we do not want to depend here on
+ * the plug-in where LayoutUtils is defined.
+ */
+ public static final int UNIT = 10;
+
+ /**
+ * The minimal amount of vertical space between the bottom of an instance
+ * role and the first element (message or execution) on its root execution
+ * for packing layout.
+ */
+ public static final int TIME_START_OFFSET = 3 * UNIT;
+
+ /**
+ * The minimal amount of vertical space between the bottom of an instance
+ * role and the first element (message or execution) on its root execution
+ * for non-packing layout.
+ */
+ public static final int TIME_START_MIN_OFFSET = 1 * UNIT;
+
+ /**
+ * The minimal amount of vertical space between the last element (message or
+ * execution) on a root execution and the bottom of the root execution.
+ */
+ public static final int TIME_STOP_OFFSET = 5 * UNIT;
+
+ /**
+ * The x position of the first left lifeline.
+ */
+ public static final int LIFELINES_START_X = 5 * UNIT;
+
+ /**
+ * The lifeline top position.
+ */
+ public static final int LIFELINES_START_Y = 5 * UNIT;
+
+ /**
+ * The minimum horizontal gap to keep between two neighboring lifelines.
+ */
+ public static final int LIFELINES_MIN_X_GAP = 1 * UNIT;
+
+ /**
+ * The minimum horizontal gap to keep between two neighboring lifelines.
+ */
+ public static final int LIFELINES_MIN_PACKED_X_GAP = 3 * UNIT;
+
+ /**
+ * The minimum vertical range upper bound for lifelines.
+ */
+ public static final int LIFELINES_MIN_Y = 20 * UNIT;
+
+ /**
+ * The minimum vertical space to leave between two successive messages.
+ */
+ public static final int MIN_INTER_SEQUENCE_EVENTS_VERTICAL_GAP = 2 * UNIT;
+
+ /**
+ * The minimum margin between the start/finish of an execution and its
+ * first/last child.
+ */
+ public static final int EXECUTION_CHILDREN_MARGIN = 5;
+
+ /**
+ * The default width used for newly created interaction uses.
+ */
+ public static final int DEFAULT_INTERACTION_USE_WIDTH = 6 * UNIT;
+
+ /**
+ * The default width used for newly created combined fragments.
+ */
+ public static final int DEFAULT_COMBINED_FRAGMENT_WIDTH = 10 * UNIT;
+
+ /**
+ * The default width used for newly created operands.
+ */
+ public static final int DEFAULT_OPERAND_WIDTH = 10 * UNIT;
+
+ /**
+ * The default height used for newly created interaction uses.
+ */
+ public static final int DEFAULT_INTERACTION_USE_HEIGHT = 5 * UNIT;
+
+ /**
+ * How much space between the top of a combined fragment and the top of its
+ * first operand.
+ */
+ public static final int COMBINED_FRAGMENT_TITLE_HEIGHT = 3 * UNIT;
+
+ /**
+ * The default height used for newly created operand.
+ */
+ public static final int DEFAULT_OPERAND_HEIGHT = 6 * UNIT;
+
+ /**
+ * The default height used for newly created combined fragments.
+ */
+ public static final int DEFAULT_COMBINED_FRAGMENT_HEIGHT = COMBINED_FRAGMENT_TITLE_HEIGHT + DEFAULT_OPERAND_HEIGHT;
+
+ /**
+ * The default height used for newly created executions.
+ */
+ public static final int DEFAULT_EXECUTION_HEIGHT = 3 * UNIT;
+
+ /**
+ * The default width used for newly created executions.
+ */
+ public static final int DEFAULT_EXECUTION_WIDTH = 2 * UNIT;
+
+ /**
+ * How much space there is between bendpoints of a message to self.
+ */
+ public static final int MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP = UNIT;
+
+ /**
+ * How much space there is between bendpoints of a message to self.
+ */
+ public static final int MESSAGE_TO_SELF_BENDPOINT_HORIZONTAL_GAP = 3 * UNIT;
+
+ /**
+ * How much space there is between bendpoints of a two included messages to
+ * self.
+ */
+ public static final int MESSAGE_TO_SELF_HORIZONTAL_GAP = 2 * UNIT;
+
+ /**
+ * The default width used for lost messages.
+ */
+ public static final int LOST_MESSAGE_DEFAULT_WIDTH = 6 * UNIT;
+
+ /** Defines the visual appearance of lifelines. */
+ public static final int[] LIFELINE_DASH_STYLE = new int[] { 10, 10 };
+
+ /** Defines the visual appearance of operands. */
+ public static final int[] OPERAND_DASH_STYLE = new int[] { 5, 5 };
+
+ /**
+ * Default height of execution after a layout, also the default height of
+ * syncCall/asyncCall execution after creation.
+ */
+ public static final int INTERACTION_EXECUTION_MIN_HEIGHT_AFTER_LAYOUT = 50;
+
+ /**
+ * Default height of execution after a layout.
+ */
+ public static final int INTERACTION_STATE_MIN_HEIGHT_AFTER_LAYOUT = 30;
+
+ /**
+ * Margin between a parent frame and its children.
+ */
+ public static final int BORDER_FRAME_MARGIN = UNIT;
+
+ /**
+ * Tool creation flag for directly created DDiagramElement.
+ */
+ public static final Rectangle TOOL_CREATION_FLAG = new Rectangle(-1, -1, 0, 0);
+
+ /**
+ * Tool creation flag for created DDiagramElement from semantic.
+ */
+ public static final Rectangle TOOL_CREATION_FLAG_FROM_SEMANTIC = new Rectangle(-1, -2, 0, 0);
+
+ /**
+ * External Reparent / Reconnect detection flag.
+ */
+ public static final Rectangle EXTERNAL_CHANGE_FLAG = new Rectangle(-2, 0, 0, 0);
+
+ private LayoutConstants() {
+ // Prevents instantiation.
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/SequenceLayout.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/SequenceLayout.java
new file mode 100644
index 0000000000..eda7496903
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/SequenceLayout.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * 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.business.internal.layout;
+
+import org.eclipse.gmf.runtime.notation.Diagram;
+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.CollapseFilter;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.business.api.query.NodeQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElementAccessor;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.flag.SequenceDiagramAbsoluteBoundsFlagger;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.horizontal.SequenceHorizontalLayout;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.observation.SequenceObservationLayout;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.vertical.SequenceVerticalLayout;
+
+/**
+ * Computes the appropriate graphical locations of sequence events and lifelines
+ * on a sequence diagram to reflect the semantic order.
+ *
+ * @author pcdavid, mporhel
+ */
+public class SequenceLayout {
+
+ private final Option<SequenceDiagram> sequenceDiagram;
+
+ private SequenceHorizontalLayout sequenceHorizontalLayout;
+
+ private SequenceVerticalLayout sequenceVerticalLayout;
+
+ private SequenceObservationLayout sequenceObservationLayout;
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the sequence diagram for which to compute the messages
+ * locations.
+ */
+ public SequenceLayout(Diagram diagram) {
+ this.sequenceDiagram = ISequenceElementAccessor.getSequenceDiagram(diagram);
+ this.sequenceHorizontalLayout = new SequenceHorizontalLayout(sequenceDiagram.get());
+ this.sequenceVerticalLayout = new SequenceVerticalLayout(sequenceDiagram.get());
+ this.sequenceObservationLayout = new SequenceObservationLayout(sequenceDiagram.get());
+ }
+
+ public Option<SequenceDiagram> getSequenceDiagram() {
+ return sequenceDiagram;
+ }
+
+ /**
+ * Compute and apply horizontal layout. Should be use in a
+ * {@link org.eclipse.emf.transaction.RecordingCommand}.
+ *
+ * @param pack
+ * pack the space between instance roles.
+ * @return true if horizontal layout has been done
+ */
+ public boolean horizontalLayout(boolean pack) {
+ if (this.sequenceHorizontalLayout != null && this.sequenceDiagram.some()) {
+ return this.sequenceHorizontalLayout.layout(pack);
+ }
+ return false;
+ }
+
+ /**
+ * Compute and apply vertical layout. Should be use in a
+ * {@link org.eclipse.emf.transaction.RecordingCommand}.
+ *
+ * @param pack
+ * pack the space between sequence events
+ * @return true if vertical layout has been done
+ */
+ public boolean verticalLayout(boolean pack) {
+ if (this.sequenceVerticalLayout != null && this.sequenceDiagram.some()) {
+ return this.sequenceVerticalLayout.layout(pack);
+ }
+ return false;
+ }
+
+ /**
+ * Compute and apply observation layout. Should be use in a
+ * {@link org.eclipse.emf.transaction.RecordingCommand} and after vertical
+ * and horizontal layout.
+ *
+ * It will place the ObservationPoint.
+ *
+ * @param pack
+ * pack the space between sequence events
+ * @return true if horizontal layout has been done
+ */
+ public boolean observationLayout(boolean pack) {
+ if (this.sequenceObservationLayout != null && this.sequenceDiagram.some()) {
+ return this.sequenceObservationLayout.layout(pack);
+ }
+ return false;
+ }
+
+ /**
+ * Flag DDiagramElement with their absolute bounds.
+ */
+ public void flagSequenceEvents() {
+ // Flag event with their new position
+ if (this.sequenceDiagram.some()) {
+ SequenceDiagramAbsoluteBoundsFlagger flagHelper = new SequenceDiagramAbsoluteBoundsFlagger(sequenceDiagram.get());
+ flagHelper.flag();
+
+ updateCollapseFilters();
+ }
+ }
+
+ private void updateCollapseFilters() {
+ for (ISequenceNode isn : Iterables.concat(sequenceDiagram.get().getAllAbstractNodeEvents(), sequenceDiagram.get().getAllObservationPoints(), sequenceDiagram.get().getAllLifelines())) {
+ Node node = isn.getNotationNode();
+ if (new NodeQuery(node).isCollapsed() && node.getElement() instanceof DDiagramElement && node.getLayoutConstraint() instanceof Size) {
+ Size size = (Size) node.getLayoutConstraint();
+ DDiagramElement dde = (DDiagramElement) node.getElement();
+ for (CollapseFilter collapseFilter : Iterables.filter(dde.getGraphicalFilters(), CollapseFilter.class)) {
+ collapseFilter.setHeight(size.getHeight());
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/AbstractSequenceAbsoluteBoundsFlagger.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/AbstractSequenceAbsoluteBoundsFlagger.java
new file mode 100644
index 0000000000..41dfc0c4fb
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/AbstractSequenceAbsoluteBoundsFlagger.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.business.internal.layout.flag;
+
+import java.util.Collection;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.AbsoluteBoundsFilter;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.SiriusFactory;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+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.layout.LayoutConstants;
+
+/**
+ * Helper to compute and attach absolute bounds flag for sequence events.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractSequenceAbsoluteBoundsFlagger {
+
+ /**
+ * Compute absolute bounds flags for each delimited sequence events of the
+ * current diagram.
+ */
+ public final void flag() {
+ for (ISequenceElement ise : getEventsToFlag()) {
+ flag(ise);
+ }
+ }
+
+ private void flag(ISequenceElement ise) {
+ // add flag
+ EObject element = ise.getNotationView().getElement();
+ if (element instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) element;
+ Rectangle absBounds = ise.getProperLogicalBounds();
+
+ AbsoluteBoundsFilter flag = getOrCreateFlag(dde);
+
+ if (ise instanceof LostMessageEnd && !((LostMessageEnd) ise).getMessage().some()) {
+ flag.setX(LayoutConstants.TOOL_CREATION_FLAG_FROM_SEMANTIC.x);
+ }
+
+ // Update flag
+ if (flag != null && absBounds != null) {
+ if (!(ise instanceof Message)) {
+ flag.setX(absBounds.x);
+ flag.setWidth(absBounds.width);
+ }
+ flag.setY(absBounds.y);
+ flag.setHeight(absBounds.height);
+ }
+ }
+ }
+
+ /**
+ * Gets events to flag.
+ *
+ * @return a collection of events to flag.
+ */
+ protected abstract Collection<ISequenceElement> getEventsToFlag();
+
+ private AbsoluteBoundsFilter getOrCreateFlag(DDiagramElement dde) {
+ AbsoluteBoundsFilter flag = null;
+ Collection<AbsoluteBoundsFilter> flags = Lists.newArrayList(Iterables.filter(dde.getGraphicalFilters(), AbsoluteBoundsFilter.class));
+ for (AbsoluteBoundsFilter prevFlag : flags) {
+ flag = prevFlag;
+ break;
+ }
+
+ if (flag == null) {
+ flag = SiriusFactory.eINSTANCE.createAbsoluteBoundsFilter();
+ dde.getGraphicalFilters().add(flag);
+ }
+ return flag;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceDiagramAbsoluteBoundsFlagger.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceDiagramAbsoluteBoundsFlagger.java
new file mode 100644
index 0000000000..30ca92ada5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceDiagramAbsoluteBoundsFlagger.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.business.internal.layout.flag;
+
+import java.util.Collection;
+import java.util.List;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+
+/**
+ * Helper to compute and attach absolute bounds flag for sequence events.
+ *
+ * @author mporhel
+ */
+public class SequenceDiagramAbsoluteBoundsFlagger extends AbstractSequenceAbsoluteBoundsFlagger {
+
+ private SequenceDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram to flag.
+ */
+ public SequenceDiagramAbsoluteBoundsFlagger(SequenceDiagram sequenceDiagram) {
+ this.diagram = sequenceDiagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceElement> getEventsToFlag() {
+ List<ISequenceElement> eventsToFlag = Lists.newArrayList();
+ if (diagram != null) {
+ Iterables.addAll(eventsToFlag, diagram.getAllDelimitedSequenceEvents());
+ Iterables.addAll(eventsToFlag, diagram.getAllLostMessageEnds());
+ Iterables.addAll(eventsToFlag, diagram.getAllInstanceRoles());
+ }
+ return eventsToFlag;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceEventAbsoluteBoundsFlagger.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceEventAbsoluteBoundsFlagger.java
new file mode 100644
index 0000000000..201dfdab79
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/flag/SequenceEventAbsoluteBoundsFlagger.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.business.internal.layout.flag;
+
+import java.util.Collection;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+
+/**
+ * Helper to compute and attach absolute bounds flag for sequence events.
+ *
+ * @author mporhel
+ */
+public class SequenceEventAbsoluteBoundsFlagger extends AbstractSequenceAbsoluteBoundsFlagger {
+
+ private ISequenceEvent ise;
+
+ /**
+ * Constructor.
+ *
+ * @param ise
+ * the sequence event to flag.
+ */
+ public SequenceEventAbsoluteBoundsFlagger(ISequenceEvent ise) {
+ this.ise = ise;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Collection<ISequenceElement> getEventsToFlag() {
+ List<ISequenceElement> eventsToFlag = Lists.newArrayList();
+ if (ise != null) {
+ eventsToFlag.add(ise);
+ }
+ return eventsToFlag;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/LostMessageEndHorizontalLayoutHelper.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/LostMessageEndHorizontalLayoutHelper.java
new file mode 100644
index 0000000000..de4e392692
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/LostMessageEndHorizontalLayoutHelper.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * 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.business.internal.layout.horizontal;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Predicate;
+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.Maps;
+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.DEdge;
+import org.eclipse.sirius.EdgeTarget;
+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.Message.Kind;
+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.AbstractSequenceLayout;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Computes the appropriate graphical locations of sequence events and lifelines
+ * on a sequence diagram to reflect the semantic order.
+ *
+ * @author pcdavid, mporhel
+ */
+public class LostMessageEndHorizontalLayoutHelper {
+
+ private final Map<LostMessageEnd, Message> lostMessages = Maps.newHashMap();
+
+ private final Multimap<Lifeline, LostMessageEnd> lostSources = HashMultimap.create();
+
+ private final Multimap<Lifeline, LostMessageEnd> lostTargets = HashMultimap.create();
+
+ private Map<LostMessageEnd, Operand> operands = Maps.newHashMap();
+
+ private Multimap<Operand, LostMessageEnd> operands2lostEnds = HashMultimap.create();
+
+ private Set<LostMessageEnd> diagramLostEnds = Sets.newHashSet();
+
+ private SequenceDiagram sequenceDiagram;
+
+ private Set<LostMessageEnd> unconnectedLostEnds = Sets.newHashSet();
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the sequence diagram for which to compute the horizontal
+ * locations.
+ */
+ public LostMessageEndHorizontalLayoutHelper(SequenceDiagram diagram) {
+ this.sequenceDiagram = diagram;
+ }
+
+ /**
+ * Populate lost message ends and helper context.
+ */
+ public void populateLostMessageEnds() {
+ for (Message msg : sequenceDiagram.getAllMessages()) {
+ populateLostEnds(msg);
+ }
+
+ registerUnconnectedLostEnds();
+ }
+
+ private void registerUnconnectedLostEnds() {
+ Predicate<LostMessageEnd> unConnectedEnds = Predicates.not(Predicates.in(lostMessages.keySet()));
+ for (LostMessageEnd lme : Iterables.filter(sequenceDiagram.getAllLostMessageEnds(), unConnectedEnds)) {
+ unconnectedLostEnds.add(lme);
+
+ // look viewpoint edges
+ if (lme.getNotationNode().getElement() instanceof EdgeTarget) {
+ EdgeTarget targetNode = getKnownTargetNode(lme);
+ if (targetNode != null) {
+ ISequenceEvent ise = getISequenceEvent(targetNode);
+ if (ise != null && ise.getLifeline().some()) {
+ lostSources.put(ise.getLifeline().get(), lme);
+ Option<Operand> parentOperand = ise.getParentOperand();
+ if (parentOperand.some()) {
+ operands.put(lme, parentOperand.get());
+ operands2lostEnds.put(parentOperand.get(), lme);
+ } else {
+ diagramLostEnds.add(lme);
+ }
+ }
+ }
+ EdgeTarget sourceNode = getKnownSourceNode(lme);
+ if (sourceNode != null) {
+ ISequenceEvent ise = getISequenceEvent(sourceNode);
+ if (ise != null && ise.getLifeline().some()) {
+ lostTargets.put(ise.getLifeline().get(), lme);
+ Option<Operand> parentOperand = ise.getParentOperand();
+ if (parentOperand.some()) {
+ operands.put(lme, parentOperand.get());
+ operands2lostEnds.put(parentOperand.get(), lme);
+ } else {
+ diagramLostEnds.add(lme);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void populateLostEnds(Message msg) {
+ ISequenceNode sourceElement = msg.getSourceElement();
+ ISequenceNode targetElement = msg.getTargetElement();
+
+ Option<Operand> parentOperand = msg.getParentOperand();
+ if (sourceElement != null && targetElement != null) {
+ Option<Lifeline> sourceLifeline = sourceElement.getLifeline();
+ Option<Lifeline> targetLifeline = targetElement.getLifeline();
+
+ // Only messages with one lost end are handled.
+ if (sourceElement instanceof LostMessageEnd && targetLifeline.some()) {
+ LostMessageEnd sourceLME = (LostMessageEnd) sourceElement;
+ lostSources.put(targetLifeline.get(), sourceLME);
+ lostMessages.put(sourceLME, msg);
+ if (parentOperand.some()) {
+ operands.put(sourceLME, parentOperand.get());
+ operands2lostEnds.put(parentOperand.get(), sourceLME);
+ } else {
+ diagramLostEnds.add(sourceLME);
+ }
+ } else if (targetElement instanceof LostMessageEnd && sourceLifeline.some()) {
+ LostMessageEnd targetLME = (LostMessageEnd) targetElement;
+ lostTargets.put(sourceLifeline.get(), targetLME);
+ lostMessages.put(targetLME, msg);
+ if (parentOperand.some()) {
+ operands.put(targetLME, parentOperand.get());
+ operands2lostEnds.put(parentOperand.get(), targetLME);
+ } else {
+ diagramLostEnds.add(targetLME);
+ }
+ }
+ }
+ }
+
+ /**
+ * Computes the delta between lostEnds and their attached lifeline.
+ *
+ * @param pack
+ * pack the space between instance roles.
+ * @return computed deltas.
+ */
+ public Map<LostMessageEnd, Integer> computeLostMessageEndDeltaWithLifeline(boolean pack) {
+ Map<LostMessageEnd, Integer> deltas = Maps.newHashMap();
+
+ for (Lifeline lifeline : sequenceDiagram.getAllLifelines()) {
+ int lifelineX = lifeline.getProperLogicalBounds().x;
+
+ // Align sources on left
+ Map<Operand, Integer> maxOpSourceDeltas = Maps.newHashMap();
+ int maxLifelineSourceDelta = 0;
+ for (LostMessageEnd lostSource : lostSources.get(lifeline)) {
+ Rectangle bounds = lostSource.getProperLogicalBounds().getCopy();
+ int delta = bounds.x - lifelineX;
+ if (pack || AbstractSequenceLayout.createdFromTool(lostSource) || AbstractSequenceLayout.createdFromExternalChange(lostSource)) {
+ delta = getFoundEndPackedX(lostSource, lifeline, lifelineX, bounds.width);
+ }
+ deltas.put(lostSource, delta);
+
+ // Force align
+ if (operands.containsKey(lostSource)) {
+ Operand op = operands.get(lostSource);
+ int opMax = 0;
+ if (maxOpSourceDeltas.containsKey(op)) {
+ opMax = maxOpSourceDeltas.get(op);
+ }
+ opMax = Math.min(opMax, delta);
+ maxOpSourceDeltas.put(op, opMax);
+ } else {
+ Kind kind = getMessageKind(lostSource);
+
+ if (!Message.Kind.CREATION.equals(kind) && !Message.Kind.DESTRUCTION.equals(kind)) {
+ maxLifelineSourceDelta = Math.min(maxLifelineSourceDelta, delta);
+ }
+ }
+ }
+
+ // Align targets on right
+ Map<Operand, Integer> maxOpTargetDeltas = Maps.newHashMap();
+ int maxLifelineTargetDelta = 0;
+ for (LostMessageEnd lostTarget : lostTargets.get(lifeline)) {
+ Rectangle bounds = lostTarget.getProperLogicalBounds().getCopy();
+ int delta = bounds.x - lifelineX;
+ if (pack || AbstractSequenceLayout.createdFromTool(lostTarget) || AbstractSequenceLayout.createdFromExternalChange(lostTarget)) {
+ delta = LayoutConstants.LOST_MESSAGE_DEFAULT_WIDTH;
+ if (lostMessages.containsKey(lostTarget)) {
+ Message message = lostMessages.get(lostTarget);
+ delta += message.getSourceElement().getProperLogicalBounds().right() - lifelineX;
+ } else if (unconnectedLostEnds.contains(lostTarget)) {
+ ISequenceEvent sourceEvent = getISequenceEvent(getKnownSourceNode(lostTarget));
+ if (sourceEvent != null) {
+ delta += sourceEvent.getProperLogicalBounds().right() - lifelineX;
+ }
+ }
+ }
+ deltas.put(lostTarget, delta);
+
+ // Force align
+ if (operands.containsKey(lostTarget)) {
+ Operand op = operands.get(lostTarget);
+ int opMax = 0;
+ if (maxOpTargetDeltas.containsKey(op)) {
+ opMax = maxOpTargetDeltas.get(op);
+ }
+ opMax = Math.max(opMax, delta);
+ maxOpTargetDeltas.put(op, opMax);
+ } else {
+ maxLifelineTargetDelta = Math.max(maxLifelineTargetDelta, delta);
+ }
+ }
+
+ // Force align
+ if (pack) {
+ for (Map.Entry<Operand, Integer> entry : maxOpSourceDeltas.entrySet()) {
+ Integer maxSourceDelta = entry.getValue();
+ for (LostMessageEnd source : Iterables.filter(operands2lostEnds.get(entry.getKey()), Predicates.in(lostSources.get(lifeline)))) {
+ deltas.put(source, maxSourceDelta);
+ }
+ }
+ for (LostMessageEnd source : Iterables.filter(lostSources.get(lifeline), Predicates.not(Predicates.in(operands.keySet())))) {
+ Kind kind = getMessageKind(source);
+
+ if (!Message.Kind.CREATION.equals(kind) && !Message.Kind.DESTRUCTION.equals(kind)) {
+ deltas.put(source, maxLifelineSourceDelta);
+ }
+ }
+ for (Map.Entry<Operand, Integer> entry : maxOpTargetDeltas.entrySet()) {
+ Integer maxTargetDelta = entry.getValue();
+ for (LostMessageEnd target : Iterables.filter(operands2lostEnds.get(entry.getKey()), Predicates.in(lostTargets.get(lifeline)))) {
+ deltas.put(target, maxTargetDelta);
+ }
+ }
+ for (LostMessageEnd target : Iterables.filter(lostTargets.get(lifeline), Predicates.not(Predicates.in(operands.keySet())))) {
+ deltas.put(target, maxLifelineTargetDelta);
+ }
+ }
+ }
+ return deltas;
+ }
+
+ private int getFoundEndPackedX(LostMessageEnd lostSourceEnd, Lifeline lifeline, int lifelineX, int lostEndWidth) {
+ int refX = lifelineX;
+ Kind kind = getMessageKind(lostSourceEnd);
+
+ if (Message.Kind.CREATION.equals(kind) && lifeline.getInstanceRole() != null) {
+ refX = lifeline.getInstanceRole().getProperLogicalBounds().x;
+ } else if (Message.Kind.DESTRUCTION.equals(kind) && lifeline.getEndOfLife().some()) {
+ refX = lifeline.getEndOfLife().get().getProperLogicalBounds().x;
+ }
+ return refX - lifelineX - LayoutConstants.LOST_MESSAGE_DEFAULT_WIDTH - lostEndWidth;
+ }
+
+ /**
+ * Get the found ends gap.
+ *
+ * @param lifeline
+ * the current lifeline.
+ * @param zone
+ * zone to get look for lost messages, can be null.
+ * @param lostEndsDelta
+ * the computed deltas with lifeline.
+ * @return the gap.
+ */
+ public int getLeftGap(Lifeline lifeline, Range zone, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ int foundEndsGap = getLostMessageEndsGap(lifeline, lostSources, zone, lostEndsDelta, true);
+ int lostMessageEndsGap = getLostMessageEndsGap(lifeline, lostTargets, zone, lostEndsDelta, true);
+ return Math.max(lostMessageEndsGap, foundEndsGap);
+ }
+
+ /**
+ * Get the lost ends gap.
+ *
+ * @param lifeline
+ * the current lifeline.
+ * @param zone
+ * zone to get look for lost messages, can be null.
+ * @param lostEndsDelta
+ * the computed deltas with lifeline.
+ * @return the gap.
+ */
+ public int getRightEndsGap(Lifeline lifeline, Range zone, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ int lostMessageEndsGap = getLostMessageEndsGap(lifeline, lostTargets, zone, lostEndsDelta, false);
+ int foundEndsGap = getLostMessageEndsGap(lifeline, lostSources, zone, lostEndsDelta, false);
+ return Math.max(lostMessageEndsGap, foundEndsGap);
+ }
+
+ private EdgeTarget getKnownSourceNode(LostMessageEnd lme) {
+ EdgeTarget sourceNode = null;
+ EdgeTarget dde = (EdgeTarget) lme.getNotationNode().getElement();
+ Iterable<DEdge> incomingEdges = Iterables.filter(dde.getIncomingEdges(), Message.viewpointElementPredicate());
+ if (!Iterables.isEmpty(incomingEdges)) {
+ DEdge msg = incomingEdges.iterator().next();
+ sourceNode = msg.getSourceNode();
+ }
+ return sourceNode;
+ }
+
+ private EdgeTarget getKnownTargetNode(LostMessageEnd lme) {
+ EdgeTarget targetNode = null;
+ EdgeTarget dde = (EdgeTarget) lme.getNotationNode().getElement();
+ Iterable<DEdge> outgoingEdges = Iterables.filter(dde.getOutgoingEdges(), Message.viewpointElementPredicate());
+ if (!Iterables.isEmpty(outgoingEdges)) {
+ DEdge msg = outgoingEdges.iterator().next();
+ targetNode = msg.getTargetNode();
+ }
+ return targetNode;
+ }
+
+ // Get the first known event in hierarchy.
+ private ISequenceEvent getISequenceEvent(EdgeTarget lostNode) {
+ ISequenceEvent correspondingEvent = null;
+ List<ISequenceEvent> knownEnds = Lists.newArrayList();
+ knownEnds.addAll(sequenceDiagram.getAllLifelines());
+ knownEnds.addAll(sequenceDiagram.getAllExecutions());
+
+ for (ISequenceEvent ise : knownEnds) {
+ if (ise.getNotationView() != null && lostNode != null && lostNode.equals(ise.getNotationView().getElement())) {
+ correspondingEvent = ise;
+ break;
+ }
+ }
+ if (correspondingEvent == null) {
+ EObject eContainer = lostNode.eContainer();
+ for (ISequenceEvent ise : knownEnds) {
+ if (ise.getNotationView() != null && eContainer != null && eContainer.equals(ise.getNotationView().getElement())) {
+ correspondingEvent = ise;
+ }
+ }
+ }
+ return correspondingEvent;
+ }
+
+ private Kind getMessageKind(LostMessageEnd lostSourceEnd) {
+ Kind kind = Message.Kind.BASIC;
+ Message message = lostMessages.get(lostSourceEnd);
+ if (message != null) {
+ kind = message.getKind();
+ } else if (unconnectedLostEnds.contains(lostSourceEnd) && lostSourceEnd.getNotationNode().getElement() instanceof EdgeTarget) {
+ EdgeTarget dde = (EdgeTarget) lostSourceEnd.getNotationNode().getElement();
+ if (!dde.getOutgoingEdges().isEmpty()) {
+ kind = Message.VIEWPOINT_MESSAGE_KIND.apply(dde.getOutgoingEdges().iterator().next());
+ }
+ }
+ return kind;
+ }
+
+ private int getLostMessageEndsGap(Lifeline lifeline, Multimap<Lifeline, LostMessageEnd> lostEnds, Range zone, Map<LostMessageEnd, Integer> lostEndsDelta, boolean revertDelta) {
+ int gap = 0;
+ if (lostEnds.containsKey(lifeline)) {
+ int maxLostEndWidth = 0;
+ int maxDelta = 0;
+ int frameBorder = 0;
+ for (LostMessageEnd lme : lostEnds.get(lifeline)) {
+ // Message in zone ?
+ if (zone == null || lostMessages.containsKey(lme) && zone.includesAtLeastOneBound(lostMessages.get(lme).getVerticalRange())) {
+ int delta = lostEndsDelta.get(lme);
+ maxDelta = Math.max(maxDelta, revertDelta ? -delta : delta);
+ if (maxDelta > 0) {
+ frameBorder = LayoutConstants.BORDER_FRAME_MARGIN;
+ maxLostEndWidth = Math.max(maxLostEndWidth, lme.getProperLogicalBounds().width);
+ }
+ }
+ }
+ gap = maxDelta + maxLostEndWidth + frameBorder;
+ }
+ return gap;
+ }
+
+ /**
+ * Dispose the helper context.
+ */
+ public void dispose() {
+ operands.clear();
+ operands2lostEnds.clear();
+ diagramLostEnds.clear();
+ lostMessages.clear();
+ lostSources.clear();
+ lostTargets.clear();
+ unconnectedLostEnds.clear();
+ }
+
+ /**
+ * Compute the lost message ends futur locations.
+ *
+ * @param irMoves
+ * computed instance roles new locations.
+ * @param lostEndsDelta
+ * computed delats between lost message ends and lifelines.
+ * @return lost message ends locations.
+ */
+ public Map<LostMessageEnd, Rectangle> computeLostMessageEndsHorizontalBounds(Map<InstanceRole, Rectangle> irMoves, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ Map<LostMessageEnd, Rectangle> lostMessageEndMoves = Maps.newHashMap();
+
+ for (Lifeline lifeline : sequenceDiagram.getAllLifelines()) {
+ int newLifelineX = getNewLifelineX(lifeline, irMoves);
+
+ // Compute new ends x.
+ for (LostMessageEnd lostSource : Iterables.concat(lostSources.get(lifeline), lostTargets.get(lifeline))) {
+ int deltaWithLifeline = lostEndsDelta.get(lostSource);
+ Rectangle bounds = lostSource.getProperLogicalBounds().getCopy();
+
+ bounds.x = newLifelineX + deltaWithLifeline;
+ lostMessageEndMoves.put(lostSource, bounds);
+ }
+ }
+ return lostMessageEndMoves;
+ }
+
+ private int getNewLifelineX(Lifeline lifeline, Map<InstanceRole, Rectangle> irMoves) {
+ int lifelineOldX = lifeline.getProperLogicalBounds().x;
+ InstanceRole instanceRole = lifeline.getInstanceRole();
+
+ int deltaX = 0;
+ if (instanceRole != null && irMoves.containsKey(instanceRole)) {
+ Rectangle irBounds = instanceRole.getProperLogicalBounds().getCopy();
+ Rectangle irFutureBounds = irMoves.get(instanceRole);
+
+ deltaX = irFutureBounds.x - irBounds.x;
+ }
+ return lifelineOldX + deltaX;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/SequenceHorizontalLayout.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/SequenceHorizontalLayout.java
new file mode 100644
index 0000000000..b9d75d0b76
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/horizontal/SequenceHorizontalLayout.java
@@ -0,0 +1,656 @@
+/*******************************************************************************
+ * 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.business.internal.layout.horizontal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Bendpoints;
+import org.eclipse.gmf.runtime.notation.Bounds;
+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.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+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.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Ordering;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+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.AbstractNodeEvent;
+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.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.elements.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.AbstractSequenceOrderingLayout;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceElementQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Computes the appropriate graphical locations of sequence events and lifelines
+ * on a sequence diagram to reflect the semantic order.
+ *
+ * @author pcdavid, mporhel
+ */
+public class SequenceHorizontalLayout extends AbstractSequenceOrderingLayout<ISequenceElement, Rectangle, InstanceRole> {
+
+ private static final Function<Rectangle, Integer> RECT_TO_X = new Function<Rectangle, Integer>() {
+ public Integer apply(Rectangle input) {
+ return input.x;
+ }
+ };
+
+ private final Insets padding = new Insets(LayoutConstants.LIFELINES_START_Y, LayoutConstants.LIFELINES_START_X, 0, LayoutConstants.LIFELINES_MIN_X_GAP - LayoutConstants.LIFELINES_START_X);
+
+ private final Collection<AbstractFrame> frames = Lists.newArrayList();
+
+ private final Multimap<AbstractFrame, Lifeline> coverage = HashMultimap.create();
+
+ private final Multimap<Lifeline, AbstractFrame> invCoverage = HashMultimap.create();
+
+ private final Map<AbstractFrame, Range> ranges = Maps.newHashMap();
+
+ private final Map<AbstractFrame, Integer> frameChildrenDepths = Maps.newHashMap();
+
+ private final Map<Lifeline, Integer> lifelineChildrenDepths = Maps.newHashMap();
+
+ private LostMessageEndHorizontalLayoutHelper lostMessageEndHorizontalLayoutHelper;
+
+ private final Map<Message, Integer> reflexiveMessagesToLayout = Maps.newHashMap();
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the sequence diagram for which to compute the horizontal
+ * locations.
+ */
+ public SequenceHorizontalLayout(SequenceDiagram diagram) {
+ super(diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void init(boolean pack) {
+ if (pack) {
+ this.padding.left = LayoutConstants.LIFELINES_START_X;
+ this.padding.right = LayoutConstants.LIFELINES_MIN_PACKED_X_GAP - LayoutConstants.LIFELINES_START_X;
+ }
+
+ populateSortedIntanceRoles();
+
+ populateLifelineDepth();
+ populateFrames();
+ populateLostMessageEnds();
+
+ populateReflexiveMessages();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Rectangle getOldLayoutData(ISequenceElement ise) {
+ return ise.getProperLogicalBounds();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Map<ISequenceElement, Rectangle> computeLayout(boolean pack) {
+ LinkedHashMap<ISequenceElement, Rectangle> allMoves = Maps.newLinkedHashMap();
+
+ Map<LostMessageEnd, Integer> lostEndsDelta = lostMessageEndHorizontalLayoutHelper.computeLostMessageEndDeltaWithLifeline(pack);
+ Map<Message, Rectangle> reflexiveMessagesMoves = computeReflexiveMessagesHorizontalBounds();
+
+ Map<InstanceRole, Rectangle> irMoves = computeInstanceRoleHorizontalLocations(pack, lostEndsDelta);
+ Map<LostMessageEnd, Rectangle> lostMessageEndMoves = lostMessageEndHorizontalLayoutHelper.computeLostMessageEndsHorizontalBounds(irMoves, lostEndsDelta);
+ Map<AbstractFrame, Rectangle> frameMoves = computeFrameHorizontalBounds(irMoves, lostEndsDelta);
+
+ allMoves.putAll(irMoves);
+ allMoves.putAll(frameMoves);
+ allMoves.putAll(lostMessageEndMoves);
+ allMoves.putAll(reflexiveMessagesMoves);
+ return allMoves;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean applyComputedLayout(Map<? extends ISequenceElement, Rectangle> bounds, boolean pack) {
+ boolean applied = false;
+
+ applied = layoutInstanceRoles(bounds, pack) || applied;
+ applied = layoutFrames(bounds, pack) || applied;
+ applied = layoutLostMessageEnds(bounds, pack) || applied;
+ applied = layoutReflexiveMessages(bounds, pack) || applied;
+
+ // if (pack) {
+ // correctGmfLocations();
+ // }
+
+ return applied;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void dispose() {
+ frameChildrenDepths.clear();
+ lifelineChildrenDepths.clear();
+ coverage.clear();
+ invCoverage.clear();
+ ranges.clear();
+ frames.clear();
+ lostMessageEndHorizontalLayoutHelper.dispose();
+ reflexiveMessagesToLayout.clear();
+
+ super.dispose();
+ }
+
+ @SuppressWarnings("unused")
+ private void correctGmfLocations() {
+ layoutAbstractNodes();
+ layoutLifeline();
+ }
+
+ private void layoutLifeline() {
+ for (Lifeline lifeline : sequenceDiagram.getAllLifelines()) {
+ Rectangle properLogicalBounds = lifeline.getProperLogicalBounds();
+ Rectangle parentLogicalBounds = lifeline.getInstanceRole().getProperLogicalBounds();
+ LayoutConstraint layoutConstraint = lifeline.getNotationNode().getLayoutConstraint();
+ if (layoutConstraint instanceof Location) {
+ Location loc = (Location) layoutConstraint;
+ loc.setX(properLogicalBounds.x - parentLogicalBounds.x);
+ }
+ }
+ }
+
+ private void layoutAbstractNodes() {
+ for (AbstractNodeEvent exec : sequenceDiagram.getAllAbstractNodeEvents()) {
+ Rectangle properLogicalBounds = exec.getProperLogicalBounds();
+ Rectangle parentLogicalBounds = exec.getHierarchicalParentEvent().getProperLogicalBounds();
+ LayoutConstraint layoutConstraint = exec.getNotationNode().getLayoutConstraint();
+ if (layoutConstraint instanceof Location) {
+ Location loc = (Location) layoutConstraint;
+ loc.setX(properLogicalBounds.x - parentLogicalBounds.x);
+ }
+ }
+ }
+
+ private void populateSortedIntanceRoles() {
+ // Graphicall order
+ graphicalOrdering.addAll(sequenceDiagram.getSortedInstanceRole());
+
+ // If a semantic order is specified, sort the instance roles.
+ semanticOrdering.addAll(graphicalOrdering);
+ SequenceDDiagram sequenceDDiagram = sequenceDiagram.getSequenceDDiagram();
+ if (sequenceDDiagram != null && !sequenceDDiagram.getInstanceRoleSemanticOrdering().getSemanticInstanceRoles().isEmpty()) {
+ final List<EObject> semanticOrder = sequenceDDiagram.getInstanceRoleSemanticOrdering().getSemanticInstanceRoles();
+ Function<InstanceRole, Integer> semanticIndex = new Function<InstanceRole, Integer>() {
+ public Integer apply(InstanceRole ir) {
+ Option<EObject> semIr = ir.getSemanticTargetElement();
+ return semIr.some() ? semanticOrder.indexOf(semIr.get()) : -1;
+ }
+ };
+ Collections.sort(semanticOrdering, Ordering.natural().onResultOf(semanticIndex));
+ }
+
+ for (InstanceRole role : semanticOrdering) {
+ ISequenceElementQuery query = new ISequenceElementQuery(role);
+ if (query.hasAbsoluteBoundsFlag()) {
+ Rectangle flaggedAbsoluteBounds = query.getFlaggedAbsoluteBounds();
+ oldFlaggedLayoutData.put(role, flaggedAbsoluteBounds);
+ flaggedEnds.add(role);
+ }
+ }
+
+ Collections.sort(flaggedEnds, Ordering.natural().onResultOf(getOldFlaggedPosition()));
+ }
+
+ private void populateLifelineDepth() {
+ List<Lifeline> allLifelines = sequenceDiagram.getAllLifelines();
+ for (Lifeline lifeline : allLifelines) {
+ int depth = getOrComputeMaxChildrenDepth(lifeline.getNotationNode(), lifeline.getVerticalRange());
+ lifelineChildrenDepths.put(lifeline, depth);
+ }
+ }
+
+ private void populateLostMessageEnds() {
+ lostMessageEndHorizontalLayoutHelper = new LostMessageEndHorizontalLayoutHelper(sequenceDiagram);
+ lostMessageEndHorizontalLayoutHelper.populateLostMessageEnds();
+ }
+
+ private void populateFrames() {
+ Collection<AbstractFrame> allFrames = Lists.newArrayList();
+ allFrames.addAll(sequenceDiagram.getAllInteractionUses());
+ allFrames.addAll(sequenceDiagram.getAllCombinedFragments());
+
+ for (AbstractFrame frame : allFrames) {
+ Collection<Lifeline> coveredLifelines = frame.computeCoveredLifelines();
+ if (!coveredLifelines.isEmpty()) {
+ frames.add(frame);
+ coverage.putAll(frame, coveredLifelines);
+ ranges.put(frame, frame.getVerticalRange());
+ }
+ }
+
+ for (AbstractFrame frame : frames) {
+ getOrComputeMaxChildrenDepth(frame, Collections.singletonList(frame));
+ }
+
+ Multimaps.invertFrom(coverage, invCoverage);
+ }
+
+ private void populateReflexiveMessages() {
+ for (Message msg : sequenceDiagram.getAllMessages()) {
+ if (msg.isReflective()) {
+ int width = msg.getReflexiveMessageWidth();
+ if (width != 0) {
+ reflexiveMessagesToLayout.put(msg, width);
+ }
+ }
+ }
+
+ }
+
+ private int getOrComputeMaxChildrenDepth(Node node, Range range) {
+ int maxChildrenDepth = 0;
+ for (Node child : Iterables.filter(Iterables.filter(node.getChildren(), Node.class), AbstractNodeEvent.notationPredicate())) {
+ AbstractNodeEvent childExec = ISequenceElementAccessor.getAbstractNodeEvent(child).get();
+ if (range == null || range.intersects(childExec.getVerticalRange())) {
+ int childDepth = 1 + getOrComputeMaxChildrenDepth(child, range);
+ maxChildrenDepth = Math.max(childDepth, maxChildrenDepth);
+ }
+ }
+ return maxChildrenDepth;
+ }
+
+ private int getOrComputeMaxChildrenDepth(AbstractFrame frame, Collection<AbstractFrame> framesToIgnore) {
+ int children = 0;
+ if (!frameChildrenDepths.containsKey(frame)) {
+ Collection<Lifeline> frameCoverage = coverage.get(frame);
+ Range frameRange = ranges.get(frame);
+ for (AbstractFrame potentialChild : Iterables.filter(frames, Predicates.not(Predicates.in(framesToIgnore)))) {
+ Collection<Lifeline> potentialCoverage = coverage.get(potentialChild);
+ Range potentialRange = ranges.get(potentialChild);
+
+ if (frame != potentialChild && frameCoverage.containsAll(potentialCoverage) && frameRange.includes(potentialRange)) {
+ ArrayList<AbstractFrame> newArrayList = Lists.newArrayList(framesToIgnore);
+ newArrayList.add(potentialChild);
+ children = Math.max(children, 1 + getOrComputeMaxChildrenDepth(potentialChild, newArrayList));
+ }
+ }
+ frameChildrenDepths.put(frame, children);
+ } else {
+ children = frameChildrenDepths.get(frame);
+ }
+ return children;
+ }
+
+ private Map<AbstractFrame, Rectangle> computeFrameHorizontalBounds(Map<InstanceRole, Rectangle> irMoves, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ Map<AbstractFrame, Rectangle> frameMoves = Maps.newHashMap();
+
+ for (AbstractFrame frame : frames) {
+ Rectangle newBounds = null;
+ Lifeline leftLifeline = null;
+ Lifeline rightLifeline = null;
+ for (Lifeline lifeline : coverage.get(frame)) {
+ Rectangle lBounds = getInstanceRoleBounds(lifeline.getInstanceRole(), irMoves);
+ if (newBounds == null) {
+ newBounds = lBounds.getCopy();
+ } else {
+ newBounds.union(lBounds);
+ }
+
+ // look for right lifeline
+ if (lBounds.right() == newBounds.right()) {
+ rightLifeline = lifeline;
+ }
+
+ // look for left lifeline
+ if (lBounds.x == newBounds.x) {
+ leftLifeline = lifeline;
+ }
+ }
+
+ Integer frameDepth = frameChildrenDepths.get(frame);
+ int frameDepthGap = frameDepth * LayoutConstants.BORDER_FRAME_MARGIN;
+
+ if (rightLifeline != null) {
+ Range verticalRange = frame.getVerticalRange();
+ int irWidth = getInstanceRoleBounds(rightLifeline.getInstanceRole(), irMoves).width;
+ int lifelineRightGap = getLifelineRightGap(rightLifeline, verticalRange, irWidth, lostEndsDelta);
+ newBounds.width += Math.max(lifelineRightGap, frameDepthGap);
+ }
+
+ if (leftLifeline != null) {
+ Range verticalRange = frame.getVerticalRange();
+ int irWidth = getInstanceRoleBounds(leftLifeline.getInstanceRole(), irMoves).width;
+ int lifelineLeftGap = getLifelineLeftGap(rightLifeline, verticalRange, irWidth, lostEndsDelta);
+ lifelineLeftGap = Math.max(lifelineLeftGap, frameDepthGap);
+
+ newBounds.x -= lifelineLeftGap;
+ newBounds.width += lifelineLeftGap;
+ }
+
+ frameMoves.put(frame, newBounds);
+ }
+ return frameMoves;
+ }
+
+ private Rectangle getInstanceRoleBounds(InstanceRole instanceRole, Map<InstanceRole, Rectangle> irMoves) {
+ if (irMoves.containsKey(instanceRole)) {
+ return irMoves.get(instanceRole);
+ }
+ return instanceRole.getBounds();
+ }
+
+ /**
+ * Computes the horizontal absolute location of instance roles.
+ *
+ * @param pack
+ * pack the diagram
+ * @param lostEndsDelta
+ * @param reflexiveMessagesMoves
+ *
+ * @return a map associating each instance role edit part to the new
+ * absolute horizontal location it should have.
+ */
+ private Map<InstanceRole, Rectangle> computeInstanceRoleHorizontalLocations(boolean pack, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ final Map<InstanceRole, Rectangle> computedMoves = new HashMap<InstanceRole, Rectangle>();
+
+ // initial position
+ int currentX = padding.left;
+ for (InstanceRole instanceRole : semanticOrdering) {
+ currentX = computeLocation(currentX, instanceRole, pack, lostEndsDelta, computedMoves);
+ }
+ return computedMoves;
+ }
+
+ /**
+ * Compute and store the new bounds of the instance roles, the x location
+ * will be the only modified value. Return the next minimum x.
+ */
+ private int computeLocation(final int currentX, final InstanceRole instanceRole, boolean pack, Map<LostMessageEnd, Integer> lostEndsDelta, final Map<InstanceRole, Rectangle> computedMoves) {
+ final Rectangle oldBounds = instanceRole.getProperLogicalBounds();
+ final Option<Lifeline> lifeline = instanceRole.getLifeline();
+
+ int newMinX = currentX;
+ int rightComputedGap = 0;
+ if (lifeline.some()) {
+ int maxFrameDepth = getMaxFrameDepth(lifeline.get());
+ int foundMessagesGap = getLifelineLeftGap(lifeline.get(), null, oldBounds.width, lostEndsDelta);
+ int frameGap = maxFrameDepth * LayoutConstants.BORDER_FRAME_MARGIN;
+ int rightGap = getLifelineRightGap(lifeline.get(), null, oldBounds.width, lostEndsDelta);
+
+ // Make space for frame and found messages.
+ newMinX += frameGap + foundMessagesGap;
+ // Update computed gap
+ rightComputedGap = frameGap + rightGap;
+ }
+
+ Rectangle newBounds = oldBounds.getCopy();
+ if (pack) {
+ newBounds.x = newMinX;
+ } else {
+ // shift the current instancerole to the right ?
+ // don't reduce previous delta with known/flagged predecessor
+ int deltaStablePosition = getDeltaStablePosition(newMinX, instanceRole, Maps.transformValues(computedMoves, RECT_TO_X));
+
+ newBounds.x = Math.max(newMinX, Math.max(newBounds.x, deltaStablePosition));
+ }
+
+ // Store computed move
+ computedMoves.put(instanceRole, newBounds);
+
+ // Return the next minX : right of the current instance role + minimum
+ // gap + place for frames and found messages
+ return newBounds.right() + getMinInstanceRoleGap() + rightComputedGap;
+ }
+
+ private int getMaxReflexiveDepth(Lifeline lifeline, Range zone) {
+ int maxWidth = 0;
+ for (Message msg : reflexiveMessagesToLayout.keySet()) {
+ if (lifeline.equals(msg.getLifeline().get()) && (zone == null || zone.includes(msg.getVerticalRange()))) {
+ maxWidth = Math.max(maxWidth, reflexiveMessagesToLayout.get(msg));
+ }
+ }
+ return maxWidth;
+ }
+
+ private Map<Message, Rectangle> computeReflexiveMessagesHorizontalBounds() {
+ final Map<Message, Rectangle> computedMoves = new HashMap<Message, Rectangle>();
+ for (Message msg : reflexiveMessagesToLayout.keySet()) {
+ Rectangle properLogicalBounds = msg.getProperLogicalBounds();
+ properLogicalBounds.width = reflexiveMessagesToLayout.get(msg);
+ computedMoves.put(msg, properLogicalBounds);
+ }
+ return computedMoves;
+ }
+
+ private int getMinInstanceRoleGap() {
+ return padding.right + padding.left;
+ }
+
+ private int getMaxExecDepth(Lifeline lifeline) {
+ int depth = 0;
+ if (lifelineChildrenDepths.containsKey(lifeline)) {
+ depth = lifelineChildrenDepths.get(lifeline);
+ }
+ return depth;
+ }
+
+ private int getMaxFrameDepth(Lifeline lifeline) {
+ int depth = 0;
+ Collection<AbstractFrame> collection = invCoverage.get(lifeline);
+ if (collection != null && !collection.isEmpty()) {
+ for (AbstractFrame abstractFrame : collection) {
+ Integer integer = frameChildrenDepths.get(abstractFrame);
+ depth = Math.max(integer, depth);
+ }
+ }
+ return depth;
+ }
+
+ /**
+ * Compute the right gap for the given lifeline and range.
+ *
+ * @param lifeline
+ * the current lifeline.
+ * @param zone
+ * if not null, the restricted vertical range to look for
+ * execution and lost ends.
+ * @param irWidth
+ * the instance role width.
+ * @param lostEndsDelta
+ * @return the right gap for the current lifeline.
+ */
+ private int getLifelineRightGap(Lifeline lifeline, Range zone, int irWidth, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ int rightGap = 0;
+ int execDepth = zone == null ? getMaxExecDepth(lifeline) : getOrComputeMaxChildrenDepth(lifeline.getNotationNode(), zone);
+
+ // handle Execution and State hierarchy
+ if (execDepth != 0) {
+ // the first execution is centered on the lifeline.
+ int gap = LayoutConstants.UNIT;
+ // TODO get the execution vsm size.
+ gap += (execDepth - 1) * 15;
+ // Remove the mid instance role size to get the gap relative to its
+ // right and ad the minimum gap between last execution and frame
+ // border.
+ gap += -irWidth / 2 + LayoutConstants.UNIT;
+ rightGap = Math.max(0, gap);
+ }
+
+ // Make space for reflexive messages
+ int reflexiveGap = getMaxReflexiveDepth(lifeline, zone) - irWidth / 2;
+ rightGap = Math.max(rightGap, reflexiveGap);
+
+ // handle lost message ends
+ rightGap = Math.max(rightGap, lostMessageEndHorizontalLayoutHelper.getRightEndsGap(lifeline, zone, lostEndsDelta) - irWidth / 2);
+
+ return rightGap;
+ }
+
+ private int getLifelineLeftGap(Lifeline lifeline, Range zone, int irWidth, Map<LostMessageEnd, Integer> lostEndsDelta) {
+ int leftGap = 0;
+
+ // handle lost message ends
+ leftGap = Math.max(leftGap, lostMessageEndHorizontalLayoutHelper.getLeftGap(lifeline, zone, lostEndsDelta) - irWidth / 2);
+
+ return leftGap;
+ }
+
+ private boolean layoutInstanceRoles(Map<? extends ISequenceElement, Rectangle> bounds, boolean pack) {
+ boolean applied = false;
+ for (InstanceRole instanceRole : Iterables.filter(bounds.keySet(), InstanceRole.class)) {
+ final Node node = instanceRole.getNotationNode();
+ final Integer computedX = bounds.get(instanceRole).x;
+
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Location) {
+ Location location = (Location) layoutConstraint;
+ location.setX(computedX);
+ }
+ applied = true;
+ }
+ return applied;
+ }
+
+ private boolean layoutFrames(Map<? extends ISequenceElement, Rectangle> bounds, boolean pack) {
+ boolean applied = false;
+ for (AbstractFrame frame : Iterables.filter(bounds.keySet(), AbstractFrame.class)) {
+ Rectangle newBounds = bounds.get(frame);
+ Node notationNode = frame.getNotationNode();
+ LayoutConstraint layoutConstraint = notationNode.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds && newBounds != null) {
+ Bounds b = (Bounds) layoutConstraint;
+ b.setWidth(newBounds.width);
+ b.setX(newBounds.x);
+ applied = true;
+ }
+
+ if (frame instanceof CombinedFragment) {
+ CombinedFragment cf = (CombinedFragment) frame;
+ for (Operand op : cf.getOperands()) {
+ Node opNode = op.getNotationNode();
+ LayoutConstraint opLC = opNode.getLayoutConstraint();
+ if (opLC instanceof Bounds && newBounds != null) {
+ Bounds opBounds = (Bounds) opLC;
+ opBounds.setWidth(newBounds.width);
+ opBounds.setX(0);
+ applied = true;
+ }
+ }
+ }
+ }
+ return applied;
+ }
+
+ private boolean layoutLostMessageEnds(Map<? extends ISequenceElement, Rectangle> bounds, boolean pack) {
+ boolean applied = false;
+ for (LostMessageEnd lostMessageEnd : Iterables.filter(bounds.keySet(), LostMessageEnd.class)) {
+ final Node node = lostMessageEnd.getNotationNode();
+ final Integer computedX = bounds.get(lostMessageEnd).x;
+
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Location) {
+ Location location = (Location) layoutConstraint;
+ location.setX(computedX);
+ applied = true;
+ }
+ }
+ return applied;
+ }
+
+ private boolean layoutReflexiveMessages(Map<? extends ISequenceElement, Rectangle> bounds, boolean pack) {
+ boolean applied = false;
+ for (Message msg : Iterables.filter(bounds.keySet(), Message.class)) {
+ Bendpoints bendpoints = msg.getNotationEdge().getBendpoints();
+ if (msg.isReflective() && bendpoints instanceof RelativeBendpoints) {
+ RelativeBendpoints relativeBendpoints = (RelativeBendpoints) bendpoints;
+ Iterable<RelativeBendpoint> points = Iterables.filter(relativeBendpoints.getPoints(), RelativeBendpoint.class);
+ if (Iterables.size(points) == 4) {
+ RelativeBendpoint p0 = Iterables.get(points, 0);
+ RelativeBendpoint p1 = Iterables.get(points, 1);
+ RelativeBendpoint p2 = Iterables.get(points, 2);
+ RelativeBendpoint p3 = Iterables.get(points, 3);
+
+ int deltaX = bounds.get(msg).width - p1.getSourceX();
+ RelativeBendpoint newP1 = new RelativeBendpoint(p1.getSourceX() + deltaX, p1.getSourceY(), p1.getTargetX() + deltaX, p1.getTargetY());
+ RelativeBendpoint newP2 = new RelativeBendpoint(p2.getSourceX() + deltaX, p2.getSourceY(), p2.getTargetX() + deltaX, p2.getTargetY());
+
+ List<RelativeBendpoint> newPoints = Lists.newArrayList();
+ newPoints.add(p0);
+ newPoints.add(newP1);
+ newPoints.add(newP2);
+ newPoints.add(p3);
+
+ relativeBendpoints.setPoints(newPoints);
+ applied = true;
+ }
+ }
+ }
+ return applied;
+ }
+
+ @Override
+ protected Function<InstanceRole, Integer> getOldPosition() {
+ return new Function<InstanceRole, Integer>() {
+ public Integer apply(InstanceRole input) {
+ return input.getProperLogicalBounds().x;
+ }
+ };
+ }
+
+ @Override
+ protected Function<InstanceRole, Integer> getOldFlaggedPosition() {
+ return new Function<InstanceRole, Integer>() {
+ public Integer apply(InstanceRole input) {
+ int oldFlaggedPosition = Integer.MIN_VALUE;
+ Rectangle flaggedData = oldFlaggedLayoutData.get(input);
+ if (flaggedData != null) {
+ oldFlaggedPosition = flaggedData.x;
+ }
+ return oldFlaggedPosition;
+ }
+ };
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/observation/SequenceObservationLayout.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/observation/SequenceObservationLayout.java
new file mode 100644
index 0000000000..f390fc1778
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/observation/SequenceObservationLayout.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * 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.business.internal.layout.observation;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import com.google.common.collect.Maps;
+
+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.sequence.business.internal.elements.AbstractFrame;
+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.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.business.internal.layout.AbstractSequenceLayout;
+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;
+
+/**
+ * Computes the appropriate graphical locations of observation points on a
+ * sequence diagram.
+ *
+ * @author mporhel
+ */
+public class SequenceObservationLayout extends AbstractSequenceLayout<ObservationPoint, Point> {
+
+ private Map<EventEnd, ObservationPoint> endToObservationPoint;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram for which to compute the observation
+ * point locations.
+ */
+ public SequenceObservationLayout(SequenceDiagram sequenceDiagram) {
+ super(sequenceDiagram);
+ this.endToObservationPoint = Maps.newHashMap();
+ }
+
+ @Override
+ protected void init(boolean pack) {
+ for (ObservationPoint point : sequenceDiagram.getAllObservationPoints()) {
+ Option<EventEnd> observedEventEnd = point.getObservedEventEnd();
+
+ if (observedEventEnd.some()) {
+ endToObservationPoint.put(observedEventEnd.get(), point);
+ }
+ }
+
+ }
+
+ @Override
+ protected Map<? extends ObservationPoint, Point> computeLayout(boolean pack) {
+ HashMap<ObservationPoint, Point> computedLayout = Maps.newHashMap();
+
+ for (ISequenceEvent ise : sequenceDiagram.getAllDelimitedSequenceEvents()) {
+ Rectangle bounds = ise.getProperLogicalBounds();
+
+ List<EventEnd> foundEnds = sequenceDiagram.findEnds(ise);
+ for (EventEnd eventEnd : foundEnds) {
+ Point refPoint = null;
+ ObservationPoint observationPoint = endToObservationPoint.get(eventEnd);
+ if (observationPoint != null) {
+ if (eventEnd instanceof SingleEventEnd) {
+ SingleEventEnd see = (SingleEventEnd) eventEnd;
+ if (ise instanceof Message) {
+ Message msg = (Message) ise;
+ if (msg.isReflective()) {
+ refPoint = see.isStart() ? bounds.getTopLeft().getCopy() : bounds.getBottomRight().getCopy();
+ } else {
+ refPoint = see.isStart() ? bounds.getTopLeft().getCopy() : bounds.getBottomRight().getCopy();
+ }
+ } else if (ise instanceof AbstractFrame || ise instanceof Operand) {
+ refPoint = see.isStart() ? bounds.getTopLeft().getCopy() : bounds.getBottomLeft().getCopy();
+ } else {
+ refPoint = see.isStart() ? bounds.getTop().getCopy() : bounds.getBottom().getCopy();
+ }
+
+ } else if (eventEnd instanceof CompoundEventEnd) {
+ if (ise instanceof State && ise.isLogicallyInstantaneous()) {
+ // getcenter ?
+ refPoint = bounds.getLeft().getCopy();
+ } else if (ise instanceof Execution) {
+ SingleEventEnd see = EventEndHelper.getSingleEventEnd(eventEnd, ise.getSemanticTargetElement().get());
+ refPoint = see.isStart() ? bounds.getTop().getCopy() : bounds.getBottom().getCopy();
+ } else if (ise instanceof Operand) {
+ SingleEventEnd see = EventEndHelper.getSingleEventEnd(eventEnd, ise.getSemanticTargetElement().get());
+ refPoint = see.isStart() ? bounds.getTopLeft().getCopy() : bounds.getBottomLeft().getCopy();
+ }
+ }
+ if (refPoint != null) {
+ computedLayout.put(observationPoint, refPoint);
+ }
+ }
+ }
+ }
+
+ return computedLayout;
+ }
+
+ @Override
+ protected boolean applyComputedLayout(Map<? extends ObservationPoint, Point> finalLocations, boolean pack) {
+ boolean applied = false;
+ for (ObservationPoint point : sequenceDiagram.getAllObservationPoints()) {
+ Point computedCenter = finalLocations.get(point);
+ if (computedCenter != null) {
+ Node notationNode = point.getNotationNode();
+ Bounds bounds = (Bounds) notationNode.getLayoutConstraint();
+
+ // Center the node on the computed location.
+ int midWidth = bounds.getWidth() / 2;
+ if (bounds.getWidth() == -1) {
+ midWidth = new DNodeQuery((DNode) point.getNotationNode().getElement()).getDefaultDimension().width / 2;
+ }
+ int midHeight = bounds.getHeight() / 2;
+ if (bounds.getHeight() == -1) {
+ midHeight = new DNodeQuery((DNode) point.getNotationNode().getElement()).getDefaultDimension().height / 2;
+ }
+
+ int x = computedCenter.x - midWidth;
+ int y = computedCenter.y - midHeight;
+
+ bounds.setX(x);
+ bounds.setY(y);
+ applied = true;
+ }
+ }
+ return applied;
+ }
+
+ @Override
+ protected Point getOldLayoutData(ObservationPoint obsPoint) {
+ return obsPoint.getObservedLogicalLocation();
+ }
+
+ @Override
+ protected void dispose() {
+ this.endToObservationPoint.clear();
+
+ super.dispose();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/vertical/SequenceVerticalLayout.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/vertical/SequenceVerticalLayout.java
new file mode 100644
index 0000000000..9e3b48f756
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/layout/vertical/SequenceVerticalLayout.java
@@ -0,0 +1,1080 @@
+/*******************************************************************************
+ * 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.business.internal.layout.vertical;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Size;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+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.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.diagram.business.internal.query.DNodeQuery;
+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.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+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.ISequenceNode;
+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.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.AbstractSequenceLayout;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.AbstractSequenceOrderingLayout;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.EventEndToPositionFunction;
+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.query.ISequenceElementQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceMessageViewQuery;
+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.util.Range;
+
+/**
+ * Computes the appropriate graphical locations of sequence events and lifelines
+ * on a sequence diagram to reflect the semantic order.
+ *
+ * @author pcdavid, mporhel
+ */
+public class SequenceVerticalLayout extends AbstractSequenceOrderingLayout<ISequenceElement, Range, EventEnd> {
+
+ /**
+ * A map to link an {@link EventEnd} to the attached {@link ISequenceEvent}.
+ */
+ protected final Map<EventEnd, Message> creators;
+
+ /**
+ * A map to link an {@link EventEnd} to the attached {@link ISequenceEvent}.
+ */
+ protected final Map<EventEnd, Message> destructors;
+
+ /**
+ * A map to link an {@link EventEnd} to an attached {@link LostMessageEnd}.
+ */
+ protected final Map<EventEnd, LostMessageEnd> losts;
+
+ /**
+ * Unconnected lostMessageEnds.
+ */
+ protected final List<LostMessageEnd> unconnectedLostEnds;
+
+ /**
+ * Semantic flagged event ends at creation.
+ */
+ protected final List<EventEnd> toolCreatedEnds = Lists.newArrayList();
+
+ /**
+ * A map to link an {@link EventEnd} to the attached {@link ISequenceEvent}.
+ */
+ protected final Multimap<EventEnd, ISequenceEvent> endToISequencEvents;
+
+ /**
+ * A map to link an {@link ISequenceEvent} to its starting and ending
+ * {@link EventEnd}.
+ */
+ protected final Multimap<ISequenceEvent, EventEnd> iSequenceEventsToEventEnds;
+
+ /**
+ * A function to compute the sequence events corresponding to an event end.
+ */
+ protected final Function<EventEnd, Collection<ISequenceEvent>> eventEndToSequenceEvents = new Function<EventEnd, Collection<ISequenceEvent>>() {
+ public Collection<ISequenceEvent> apply(EventEnd from) {
+ return endToISequencEvents.get(from);
+ }
+ };
+
+ /**
+ * The global time range of the diagram. Can be udpated during layout
+ * computation.
+ */
+ protected Range timeRange;
+
+ /**
+ * A function to get the instance role height of a lifeline.
+ */
+ private final Function<Lifeline, Integer> instanceRoleHeight = new Function<Lifeline, Integer>() {
+ public Integer apply(Lifeline from) {
+ InstanceRole irep = from.getInstanceRole();
+ if (irep != null) {
+ return ((Size) irep.getNotationNode().getLayoutConstraint()).getHeight();
+ }
+ return 0;
+ }
+ };
+
+ /**
+ * An ordering to sort {@link Lifeline} regarding the height of their
+ * {@link InstanceRole}.
+ */
+ private final Ordering<Lifeline> heightOrdering = Ordering.natural().onResultOf(instanceRoleHeight);
+
+ private final Function<ISequenceEvent, Option<Range>> oldRangeFunction = new Function<ISequenceEvent, Option<Range>>() {
+ public Option<Range> apply(ISequenceEvent from) {
+ Range range = oldLayoutData.get(from);
+ if (range == null) {
+ range = Range.emptyRange();
+ }
+ return Options.newSome(range);
+ }
+ };
+
+ private final Function<ISequenceEvent, Option<Range>> oldFlaggedRange = new Function<ISequenceEvent, Option<Range>>() {
+ public Option<Range> apply(ISequenceEvent from) {
+ Rectangle rect = oldFlaggedLayoutData.get(from);
+ Range result = null;
+ if (rect != null) {
+ result = Range.verticalRange(rect);
+ }
+ return Options.newSome(result);
+ }
+ };
+
+ private final Function<EventEnd, Integer> eventEndOldPosition = new EventEndToPositionFunction(eventEndToSequenceEvents, oldRangeFunction) {
+
+ @Override
+ protected Integer getOldPositionFromRange(SingleEventEnd see, ISequenceEvent ise) {
+ Integer oldPos = super.getOldPositionFromRange(see, ise);
+
+ if (ise instanceof Message && !ise.isLogicallyInstantaneous() && see != null) {
+ // Real position (diagram initialization, message creation)
+ Message smep = (Message) ise;
+ Edge notationView = smep.getNotationEdge();
+ SequenceMessageViewQuery query = new SequenceMessageViewQuery(notationView);
+ oldPos = see.isStart() ? query.getFirstPointVerticalPosition(true) : query.getLastPointVerticalPosition(true);
+ }
+
+ return oldPos;
+ }
+
+ };
+
+ private final Function<EventEnd, Integer> eventEndOldFlaggedPosition = new EventEndToPositionFunction(eventEndToSequenceEvents, oldFlaggedRange);
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram for which to compute the messages
+ * locations.
+ */
+ public SequenceVerticalLayout(SequenceDiagram sequenceDiagram) {
+ super(sequenceDiagram);
+
+ this.iSequenceEventsToEventEnds = LinkedHashMultimap.create();
+ this.endToISequencEvents = HashMultimap.create();
+
+ this.creators = Maps.newHashMap();
+ this.destructors = Maps.newHashMap();
+ this.losts = Maps.newHashMap();
+ this.unconnectedLostEnds = Lists.newArrayList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void init(boolean pack) {
+ initSortedEventEnds(pack);
+ initLifelinesOldLayoutData();
+ initTimeBounds(pack);
+ registerEventEnds();
+
+ lookForUnconnectedLostEnd();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Range getOldLayoutData(ISequenceElement ise) {
+ Range verticalRange = Range.emptyRange();
+
+ if (ise instanceof ISequenceEvent) {
+ verticalRange = ((ISequenceEvent) ise).getVerticalRange();
+
+ if (ise instanceof Message) {
+ Message msg = (Message) ise;
+ ISequenceElementQuery query = null;
+ ISequenceNode sourceElement = msg.getSourceElement();
+ ISequenceNode targetElement = msg.getTargetElement();
+ if (sourceElement instanceof LostMessageEnd && AbstractSequenceLayout.createdFromTool((LostMessageEnd) sourceElement)) {
+ query = new ISequenceElementQuery(sourceElement);
+ } else if (targetElement instanceof LostMessageEnd && AbstractSequenceLayout.createdFromTool((LostMessageEnd) targetElement)) {
+ query = new ISequenceElementQuery(targetElement);
+ }
+
+ if (query != null && query.hasAbsoluteBoundsFlag()) {
+ Rectangle flag = query.getFlaggedAbsoluteBounds();
+ verticalRange = new Range(flag.y, flag.y);
+ }
+ }
+ }
+
+ return verticalRange;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean applyComputedLayout(Map<? extends ISequenceElement, Range> finalRanges, boolean pack) {
+ boolean applied = false;
+ Iterable<ISequenceEvent> keySet = Iterables.filter(finalRanges.keySet(), ISequenceEvent.class);
+
+ // Begin with lifelines and executions (anchor positions move)
+ for (ISequenceEvent ise : Iterables.filter(keySet, Predicates.not(Predicates.instanceOf(Message.class)))) {
+ final Range newRange = finalRanges.get(ise);
+ ise.setVerticalRange(newRange);
+ applied = true;
+ }
+
+ // Then apply computed vertical range on messages
+ for (Message smep : Iterables.filter(keySet, Message.class)) {
+ final Range newRange = finalRanges.get(smep);
+ smep.setVerticalRange(newRange);
+ applied = true;
+ }
+
+ applied = layoutUnconnectedLostMessageEnd() || applied;
+
+ return applied;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Map<? extends ISequenceElement, Range> computeLayout(boolean pack) {
+ LinkedHashMap<ISequenceEvent, Range> sequenceEventRanges = new LinkedHashMap<ISequenceEvent, Range>();
+
+ // Compute the position of each event end.
+ Map<EventEnd, Integer> endLocations = computeEndBounds(pack);
+
+ // Compute ISequenceEvent vertical ranges from event end locations.
+ Map<ISequenceEvent, Range> basicRanges = computeBasicRanges(endLocations);
+
+ // Compute punctual States vertical range
+ Map<ISequenceEvent, Range> punctualEventRanges = computePunctualEventsGraphicalRanges(endLocations, pack);
+
+ // Update lifeline size.
+ Map<ISequenceEvent, Range> lifelinesRanges = computeLifelineRanges(endLocations);
+
+ sequenceEventRanges.putAll(lifelinesRanges);
+ sequenceEventRanges.putAll(basicRanges);
+ sequenceEventRanges.putAll(punctualEventRanges);
+
+ return sequenceEventRanges;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void dispose() {
+ creators.clear();
+ destructors.clear();
+ losts.clear();
+ unconnectedLostEnds.clear();
+ toolCreatedEnds.clear();
+
+ endToISequencEvents.clear();
+ iSequenceEventsToEventEnds.clear();
+
+ super.dispose();
+ }
+
+ private Map<ISequenceEvent, Range> computePunctualEventsGraphicalRanges(Map<EventEnd, Integer> endLocations, boolean pack) {
+ final Map<ISequenceEvent, Range> sequenceEventsToRange = new LinkedHashMap<ISequenceEvent, Range>();
+ if (pack) {
+ for (EventEnd cee : Iterables.filter(semanticOrdering, EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END)) {
+ if (endLocations.containsKey(cee) && endToISequencEvents.containsKey(cee)) {
+ int loc = endLocations.get(cee);
+ Collection<ISequenceEvent> ises = endToISequencEvents.get(cee);
+
+ if (Iterables.any(ises, Predicates.instanceOf(State.class)) && ises.size() == 1) {
+ State ise = (State) ises.iterator().next();
+ int midSize = getAbstractNodeEventVerticalSize(cee, ise, ises, pack) / 2;
+ sequenceEventsToRange.put(ise, new Range(loc - midSize, loc + midSize));
+ }
+ }
+ }
+ }
+ return sequenceEventsToRange;
+ }
+
+ /**
+ * Computes the absolute vertical (Y) location for all the messages in the
+ * sequence diagram.
+ *
+ * @return a map associating each message edit part to the new absolute
+ * vertical location it should have.
+ */
+ private Map<EventEnd, Integer> computeEndBounds(boolean pack) {
+ final Map<EventEnd, Integer> result = Maps.newLinkedHashMap();
+
+ if (semanticOrdering == null || semanticOrdering.isEmpty()) {
+ return result;
+ }
+
+ // current y location
+ int currentY = this.timeRange.getLowerBound();
+
+ EventEnd endBefore = null;
+ for (EventEnd end : semanticOrdering) {
+ currentY = computeLocation(currentY, end, endBefore, pack, result);
+ result.put(end, currentY);
+ endBefore = end;
+ }
+ return result;
+ }
+
+ private int getGapFromCommonSequenceEvent(EventEnd end, Collection<ISequenceEvent> commonIses, boolean pack, int genericGap) {
+ int beforeGap = genericGap;
+
+ if (commonIses.isEmpty()) {
+ return beforeGap;
+ }
+
+ ISequenceEvent commonIse = commonIses.iterator().next();
+ if (commonIse instanceof Message && ((Message) commonIse).isReflective()) {
+ beforeGap = LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ } else if (commonIse instanceof AbstractNodeEvent) {
+ beforeGap = Math.max(genericGap, getAbstractNodeEventVerticalSize(end, (AbstractNodeEvent) commonIse, commonIses, pack));
+ } else if (commonIse instanceof InteractionUse) {
+ beforeGap = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT;
+ } else if (commonIse instanceof Operand) {
+ beforeGap = LayoutConstants.DEFAULT_OPERAND_HEIGHT;
+ }
+ return beforeGap;
+ }
+
+ private int getAbstractNodeEventVerticalSize(EventEnd end, AbstractNodeEvent ise, Collection<ISequenceEvent> commonIses, boolean pack) {
+ int vSize = 0;
+ if (pack) {
+ DNode execution = (DNode) ise.getNotationView().getElement();
+ int specifiedVSize = getSpecifiedVSize(execution);
+ if (specifiedVSize != 0) {
+ vSize = specifiedVSize;
+ }
+ } else if (isFlagguedByRefreshExtension(end, commonIses)) {
+ Rectangle rect = oldFlaggedLayoutData.get(ise);
+ vSize = rect != null ? rect.height : LayoutConstants.DEFAULT_EXECUTION_HEIGHT;
+ } else {
+ Range range = oldLayoutData.get(ise);
+ vSize = range != null ? range.width() : LayoutConstants.DEFAULT_EXECUTION_HEIGHT;
+ }
+
+ return vSize;
+ }
+
+ private Map<ISequenceEvent, Range> computeBasicRanges(Map<EventEnd, Integer> endLocations) {
+ final Map<ISequenceEvent, Range> sequenceEventsToRange = new LinkedHashMap<ISequenceEvent, Range>();
+ Predicate<ISequenceEvent> notMoved = Predicates.not(Predicates.in(sequenceEventsToRange.keySet()));
+
+ // CombinedFragments
+ for (EventEnd sortedEnd : semanticOrdering) {
+ Predicate<ISequenceEvent> frames = Predicates.and(notMoved, Predicates.or(Predicates.instanceOf(CombinedFragment.class), Predicates.instanceOf(InteractionUse.class)));
+ for (ISequenceEvent ise : Iterables.filter(endToISequencEvents.get(sortedEnd), frames)) {
+ computeFinalRange(endLocations, sequenceEventsToRange, ise);
+ }
+ }
+
+ // Operands
+ for (EventEnd sortedEnd : semanticOrdering) {
+ Predicate<ISequenceEvent> operands = Predicates.and(notMoved, Predicates.instanceOf(Operand.class));
+ for (ISequenceEvent ise : Iterables.filter(endToISequencEvents.get(sortedEnd), operands)) {
+ computeFinalRange(endLocations, sequenceEventsToRange, ise);
+ }
+ }
+
+ // Other sequence events
+ for (EventEnd sortedEnd : semanticOrdering) {
+ for (ISequenceEvent ise : Iterables.filter(endToISequencEvents.get(sortedEnd), notMoved)) {
+ computeFinalRange(endLocations, sequenceEventsToRange, ise);
+ }
+ }
+ return sequenceEventsToRange;
+ }
+
+ private void computeFinalRange(Map<EventEnd, Integer> endLocations, final Map<ISequenceEvent, Range> sequenceEventsToRange, ISequenceEvent ise) {
+ Collection<EventEnd> ends = iSequenceEventsToEventEnds.get(ise);
+ if (ends.size() == 2) {
+ Iterator<EventEnd> it = ends.iterator();
+ EventEnd start = it.next();
+ EventEnd finish = it.next();
+
+ Range newRange = getNewRange(ise, start, finish, endLocations);
+ sequenceEventsToRange.put(ise, newRange);
+ } else if (ends.size() == 1 && ise.isLogicallyInstantaneous() && (ise instanceof Message || EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(ends.iterator().next()))) {
+ Iterator<EventEnd> it = ends.iterator();
+ EventEnd middle = it.next();
+
+ Range newRange = getNewRange(ise, middle, middle, endLocations);
+ sequenceEventsToRange.put(ise, newRange);
+ }
+ }
+
+ private Range getNewRange(final ISequenceEvent event, final EventEnd start, final EventEnd end, final Map<EventEnd, Integer> endLocations) {
+ Range oldRange = oldLayoutData.containsKey(event) ? oldLayoutData.get(event) : Range.emptyRange();
+ int lowerBound = endLocations.containsKey(start) ? endLocations.get(start) : oldRange.getLowerBound();
+ int upperBound = endLocations.containsKey(end) ? endLocations.get(end) : oldRange.getUpperBound();
+
+ if (event.isLogicallyInstantaneous() && start == end) {
+ lowerBound = lowerBound - oldRange.width() / 2;
+ upperBound = lowerBound + oldRange.width();
+ }
+
+ updateTimerange(upperBound);
+ return new Range(lowerBound, upperBound);
+ }
+
+ private Map<ISequenceEvent, Range> computeLifelineRanges(Map<EventEnd, Integer> endLocations) {
+ final Map<ISequenceEvent, Range> sequenceEventsToRange = new LinkedHashMap<ISequenceEvent, Range>();
+ int endOfLife = timeRange.getUpperBound() + LayoutConstants.TIME_STOP_OFFSET;
+
+ layoutLifelinesWithoutCreation(sequenceEventsToRange);
+ layoutCreatedLifelines(endLocations, sequenceEventsToRange);
+ layoutDestructedLifelines(endLocations, sequenceEventsToRange);
+ layoutNonDestructedLifelines(sequenceEventsToRange, Math.max(endOfLife, LayoutConstants.LIFELINES_MIN_Y));
+
+ return sequenceEventsToRange;
+ }
+
+ private void layoutLifelinesWithoutCreation(final Map<ISequenceEvent, Range> sequenceEventsToRange) {
+ for (ISequenceEvent event : getLifeLinesWithoutCreation()) {
+ Range oldRange = oldLayoutData.get(event);
+ Option<Lifeline> parentLifeline = event.getLifeline();
+ if (parentLifeline.some()) {
+ InstanceRole instanceRole = parentLifeline.get().getInstanceRole();
+ if (instanceRole != null) {
+ int newLBound = getLifelineMinLowerBound(instanceRole);
+ if (newLBound != oldRange.getLowerBound()) {
+ sequenceEventsToRange.put(event, new Range(newLBound, oldRange.getUpperBound()));
+ }
+ }
+ }
+ }
+ }
+
+ private void layoutCreatedLifelines(Map<EventEnd, Integer> endLocations, final Map<ISequenceEvent, Range> sequenceEventsToRange) {
+ for (Message smep : creators.values()) {
+ Collection<EventEnd> ends = iSequenceEventsToEventEnds.get(smep);
+ if (!ends.isEmpty()) {
+ Iterator<EventEnd> it = ends.iterator();
+ EventEnd first = it.next();
+ if (endLocations.containsKey(first)) {
+ int endMove = endLocations.get(first);
+ int vGap = getTargetFigureMidHeight(smep);
+ Lifeline lep = smep.getTargetElement().getLifeline().get();
+ Range oldRange = sequenceEventsToRange.containsKey(lep) ? sequenceEventsToRange.get(lep) : oldLayoutData.get(lep);
+ sequenceEventsToRange.put(lep, new Range(endMove + vGap, endMove + vGap + oldRange.width()));
+ }
+ }
+ }
+ }
+
+ private void layoutDestructedLifelines(Map<EventEnd, Integer> endLocations, final Map<ISequenceEvent, Range> sequenceEventsToRange) {
+ for (Message smep : destructors.values()) {
+ Collection<EventEnd> ends = iSequenceEventsToEventEnds.get(smep);
+ if (!ends.isEmpty()) {
+ Iterator<EventEnd> it = ends.iterator();
+ EventEnd first = it.next();
+ int endMove = endLocations.get(first);
+ int vGap = getTargetFigureMidHeight(smep);
+ int newY = endMove - vGap;
+ Lifeline lep = ((EndOfLife) smep.getTargetElement()).getLifeline().get();
+ Range oldRange = sequenceEventsToRange.containsKey(lep) ? sequenceEventsToRange.get(lep) : oldLayoutData.get(lep);
+ sequenceEventsToRange.put(lep, new Range(oldRange.getLowerBound(), newY));
+ }
+ }
+ }
+
+ private void layoutNonDestructedLifelines(final Map<ISequenceEvent, Range> sequenceEventsToRange, int endOfLife) {
+ // update lifeline ranges
+ for (ISequenceEvent event : getLifeLinesWithoutDestruction()) {
+ Range currentRange = sequenceEventsToRange.containsKey(event) ? sequenceEventsToRange.get(event) : oldLayoutData.get(event);
+ if (currentRange.getUpperBound() != endOfLife) {
+ sequenceEventsToRange.put(event, new Range(currentRange.getLowerBound(), endOfLife));
+ }
+ }
+ }
+
+ private int computeLocation(final int currentY, final EventEnd end, final EventEnd endBefore, final boolean pack, Map<EventEnd, Integer> alreadyComputedLocations) {
+ int location = currentY;
+ Collection<ISequenceEvent> commonIses = getCommonISequenceEvent(endBefore, end);
+
+ if (shouldMove(commonIses)) {
+ int newMinY = getMinY(endBefore, end, commonIses, pack, location, alreadyComputedLocations);
+ if (pack) {
+ location = newMinY;
+ } else {
+ // try to save position
+ int oldPosition = getOldStablePosition(currentY, end);
+
+ // don't minimize previous range
+ int rangeStableY = getRangeStablePosition(currentY, end, alreadyComputedLocations);
+
+ // don't reduce previous delta with known/flagged predecessor
+ int deltaStableY = getDeltaStablePosition(currentY, end, alreadyComputedLocations);
+
+ location = Math.max(newMinY, Math.max(oldPosition, Math.max(deltaStableY, rangeStableY)));
+ }
+ }
+ return location;
+ }
+
+ private int getOldStablePosition(final int currentY, final EventEnd end) {
+ int oldPosition = currentY;
+
+ // Should we trust GMF positions ?
+ if (flaggedEnds.contains(end) || toolCreatedEnds.contains(end)) {
+ oldPosition = eventEndOldPosition.apply(end);
+ }
+
+ if (isFlagguedByRefreshExtension(end, endToISequencEvents.get(end))) {
+ oldPosition = eventEndOldFlaggedPosition.apply(end);
+ }
+
+ return oldPosition;
+ }
+
+ private int getRangeStablePosition(final int currentY, final EventEnd end, Map<EventEnd, Integer> alreadyComputedLocations) {
+ int rangeStabilityPos = currentY;
+ Collection<ISequenceEvent> ises = endToISequencEvents.get(end);
+ for (ISequenceEvent ise : ises) {
+ if (!ise.isLogicallyInstantaneous()) {
+ SingleEventEnd see = EventEndHelper.getSingleEventEnd(end, ise.getSemanticTargetElement().get());
+ if (!see.isStart() && !(ise instanceof Message && !Iterables.isEmpty(Iterables.filter(iSequenceEventsToEventEnds.get(ise), CompoundEventEnd.class)))) {
+ int startLocation = getStartLocation(ise, alreadyComputedLocations);
+ Option<Range> oldRange = oldRangeFunction.apply(ise);
+
+ if (isFlagguedByRefreshExtension(end, Collections.singleton(ise))) {
+ oldRange = oldFlaggedRange.apply(ise);
+ }
+
+ int width = oldRange.some() ? oldRange.get().width() : 0;
+ rangeStabilityPos = Math.max(rangeStabilityPos, startLocation + width);
+ }
+ }
+ }
+ return rangeStabilityPos;
+ }
+
+ private boolean isFlagguedByRefreshExtension(EventEnd end, Collection<ISequenceEvent> ises) {
+ if (flaggedEnds.contains(end)) {
+ for (ISequenceEvent ise : ises) {
+ Rectangle flaggedAbsoluteBounds = new ISequenceElementQuery(ise).getFlaggedAbsoluteBounds();
+ if (flaggedAbsoluteBounds.x == LayoutConstants.EXTERNAL_CHANGE_FLAG.x) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean shouldMove(Collection<ISequenceEvent> commonIses) {
+ boolean shouldMove = true;
+ if (!commonIses.isEmpty()) {
+ ISequenceEvent commonIse = commonIses.iterator().next();
+ shouldMove = !commonIse.isLogicallyInstantaneous();
+ }
+
+ return shouldMove;
+ }
+
+ private int getMinY(EventEnd endBefore, EventEnd end, Collection<ISequenceEvent> commonIses, boolean pack, int currentLocation, Map<EventEnd, Integer> alreadyComputedLocations) {
+ int genericGap = getGenericGap(endBefore, end, pack);
+ int minGap = genericGap;
+
+ if (!commonIses.isEmpty()) {
+ int commonIseGap = getGapFromCommonSequenceEvent(end, commonIses, pack, genericGap);
+ minGap = commonIseGap;
+ } else {
+ boolean operands = Iterables.any(eventEndToSequenceEvents.apply(end), Predicates.instanceOf(Operand.class));
+ if (operands) {
+ minGap = getGapBeforeOperandEnd(endBefore, end, currentLocation, genericGap, alreadyComputedLocations);
+ }
+ }
+
+ return currentLocation + minGap;
+ }
+
+ private int getGenericGap(EventEnd endBefore, EventEnd end, boolean pack) {
+ int beforeGap = 0;
+
+ if (endBefore != null) {
+ Collection<ISequenceEvent> endBeforeEvents = eventEndToSequenceEvents.apply(endBefore);
+ beforeGap = pack ? LayoutConstants.MIN_INTER_SEQUENCE_EVENTS_VERTICAL_GAP : LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+
+ // Predecessor : Logically instantaneouse States
+ Iterable<State> predStates = Iterables.filter(endBeforeEvents, State.class);
+ if (EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(endBefore) && endBeforeEvents.size() == 1 && Iterables.size(predStates) == 1) {
+ State predState = Iterables.getOnlyElement(predStates);
+ if (predState.isLogicallyInstantaneous()) {
+ beforeGap += getAbstractNodeEventVerticalSize(endBefore, predState, endBeforeEvents, pack) / 2;
+ }
+ }
+
+ if (Iterables.any(endBeforeEvents, Predicates.instanceOf(InteractionUse.class)) && endBefore instanceof SingleEventEnd && ((SingleEventEnd) endBefore).isStart()) {
+ beforeGap = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT / 2;
+ }
+
+ if (Iterables.any(eventEndToSequenceEvents.apply(end), Predicates.instanceOf(InteractionUse.class)) && end instanceof SingleEventEnd && !((SingleEventEnd) end).isStart()) {
+ beforeGap = LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT / 2;
+ }
+
+ if (creators.keySet().contains(endBefore)) {
+ if (pack) {
+ beforeGap += getTargetFigureMidHeight(creators.get(endBefore)) + LayoutConstants.TIME_START_OFFSET - LayoutConstants.MIN_INTER_SEQUENCE_EVENTS_VERTICAL_GAP;
+ } else {
+ beforeGap += getTargetFigureMidHeight(creators.get(endBefore));
+ }
+ } else if (losts.containsKey(endBefore)) {
+ beforeGap += losts.get(endBefore).getBounds().height / 2;
+ }
+ } else {
+ beforeGap = pack ? LayoutConstants.TIME_START_OFFSET : LayoutConstants.TIME_START_MIN_OFFSET;
+ }
+
+ if (destructors.keySet().contains(end)) {
+ beforeGap += getTargetFigureMidHeight(destructors.get(end));
+ } else if (losts.containsKey(end)) {
+ beforeGap += losts.get(end).getBounds().height / 2;
+ }
+
+ // current event : Logically instantaneouse States
+ Collection<ISequenceEvent> endEvents = eventEndToSequenceEvents.apply(end);
+ Iterable<State> states = Iterables.filter(endEvents, State.class);
+ if (EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(end) && endEvents.size() == 1 && Iterables.size(states) == 1) {
+ State state = Iterables.getOnlyElement(states);
+ if (state.isLogicallyInstantaneous()) {
+ beforeGap += getAbstractNodeEventVerticalSize(endBefore, state, endEvents, pack) / 2;
+ }
+ }
+ return beforeGap;
+ }
+
+ private int getGapBeforeOperandEnd(EventEnd endBefore, EventEnd end, int currentLocation, int genericGap, Map<EventEnd, Integer> alreadyComputedLocations) {
+ int beforeGap = genericGap;
+ Iterable<Operand> operands = Iterables.filter(eventEndToSequenceEvents.apply(end), Operand.class);
+ if (!Iterables.isEmpty(operands) && endBefore instanceof SingleEventEnd) {
+ if (Iterables.any(eventEndToSequenceEvents.apply(endBefore), Predicates.instanceOf(CombinedFragment.class)) && ((SingleEventEnd) endBefore).isStart()) {
+ beforeGap = LayoutConstants.COMBINED_FRAGMENT_TITLE_HEIGHT;
+ } else {
+ Operand op = selectEndedOperand(end, operands);
+ if (op != null) {
+ int startLoc = getStartLocation(op, alreadyComputedLocations);
+ int minEndLoc = startLoc + LayoutConstants.DEFAULT_OPERAND_HEIGHT;
+ beforeGap = Math.max(minEndLoc - currentLocation, genericGap);
+ }
+ }
+ }
+ return beforeGap;
+ }
+
+ private Operand selectEndedOperand(EventEnd end, Iterable<Operand> operands) {
+ Operand op = null;
+ if (end instanceof CompoundEventEnd) {
+ for (SingleEventEnd see : ((CompoundEventEnd) end).getEventEnds()) {
+ if (!see.isStart()) {
+ EObject semanticEvent = see.getSemanticEvent();
+ for (Operand opp : operands) {
+ EObject eObject = opp.getSemanticTargetElement().get();
+ if (semanticEvent != null && semanticEvent.equals(eObject)) {
+ op = opp;
+ }
+ }
+ }
+ }
+ }
+ return op;
+ }
+
+ private int getStartLocation(ISequenceEvent ise, Map<EventEnd, Integer> alreadyComputedLocations) {
+ Collection<EventEnd> ends = iSequenceEventsToEventEnds.get(ise);
+ for (EventEnd end : ends) {
+ SingleEventEnd see = EventEndHelper.getSingleEventEnd(end, ise.getSemanticTargetElement().get());
+ if (see.isStart() && alreadyComputedLocations.containsKey(end)) {
+ return alreadyComputedLocations.get(end);
+ }
+ }
+ return 0;
+ }
+
+ private boolean layoutUnconnectedLostMessageEnd() {
+ boolean applied = false;
+ for (LostMessageEnd lme : unconnectedLostEnds) {
+ if (createdFromTool(lme)) {
+ ISequenceElementQuery query = new ISequenceElementQuery(lme);
+ int y = query.getFlaggedAbsoluteBounds().y;
+ if (y != -1) {
+ LayoutConstraint layoutConstraint = lme.getNotationNode().getLayoutConstraint();
+ if (layoutConstraint instanceof Location) {
+ Rectangle bounds = lme.getProperLogicalBounds();
+ ((Location) layoutConstraint).setY(y - bounds.height / 2);
+ applied = true;
+ }
+ }
+ }
+ }
+ return applied;
+ }
+
+ private void initSortedEventEnds(boolean pack) {
+ SequenceDDiagram sequenceDDiagram = (SequenceDDiagram) sequenceDiagram.getNotationDiagram().getElement();
+ graphicalOrdering.addAll(sequenceDDiagram.getGraphicalOrdering().getEventEnds());
+ semanticOrdering.addAll(sequenceDDiagram.getSemanticOrdering().getEventEnds());
+ }
+
+ private void initLifelinesOldLayoutData() {
+ Collection<Lifeline> lifelines = new ArrayList<Lifeline>();
+ lifelines.addAll(sequenceDiagram.getAllLifelines());
+ for (ISequenceEvent ise : lifelines) {
+ oldLayoutData.put(ise, getOldLayoutData(ise));
+ }
+ }
+
+ private void lookForUnconnectedLostEnd() {
+ Collection<LostMessageEnd> allLostMessageEnds = sequenceDiagram.getAllLostMessageEnds();
+ Collection<LostMessageEnd> discoveredLostEnds = Lists.newArrayList();
+ for (Message knownMsgs : Iterables.filter(iSequenceEventsToEventEnds.keySet(), Message.class)) {
+ ISequenceNode sourceElement = knownMsgs.getSourceElement();
+ if (sourceElement instanceof LostMessageEnd) {
+ discoveredLostEnds.add((LostMessageEnd) sourceElement);
+ }
+
+ ISequenceNode targetElement = knownMsgs.getTargetElement();
+ if (targetElement instanceof LostMessageEnd) {
+ discoveredLostEnds.add((LostMessageEnd) targetElement);
+ }
+ }
+
+ Iterables.removeAll(allLostMessageEnds, discoveredLostEnds);
+
+ unconnectedLostEnds.addAll(allLostMessageEnds);
+ }
+
+ /**
+ * Determines the range of absolute Y locations in which the messages can be
+ * laid out.
+ *
+ * @param pack
+ * packing layout if true.
+ * @return
+ */
+ protected void initTimeBounds(boolean pack) {
+ int minTimeBounds = getMinTimeBounds();
+ int startTime = minTimeBounds;
+ int endTime = getMaxTimeBounds(pack, minTimeBounds) - LayoutConstants.TIME_STOP_OFFSET;
+ this.timeRange = new Range(startTime, endTime);
+ }
+
+ private int getMaxTimeBounds(boolean pack, int minTimeBounds) {
+ int max = getSpecifiedMaxTimeBounds(minTimeBounds);
+
+ if (!pack) {
+ Iterable<Lifeline> lifelinesWithoutDestruction = getLifeLinesWithoutDestruction();
+
+ // Avoid to handle lifelines to move up for max computation.
+ Predicate<Lifeline> isMaxRangeCandidate = new Predicate<Lifeline>() {
+ public boolean apply(Lifeline input) {
+ InstanceRole irep = input.getInstanceRole();
+ if (irep != null) {
+ return irep.getBounds().getLocation().y <= LayoutConstants.LIFELINES_START_Y;
+ }
+ return false;
+ }
+ };
+
+ Collection<Lifeline> lifelinesToConsider = Lists.newArrayList(Iterables.filter(lifelinesWithoutDestruction, isMaxRangeCandidate));
+ Ordering<ISequenceEvent> maxOrdering = Ordering.natural().onResultOf(Functions.compose(Range.upperBoundFunction(), ISequenceEvent.VERTICAL_RANGE));
+ if (!lifelinesToConsider.isEmpty()) {
+ Lifeline lep = maxOrdering.max(lifelinesToConsider);
+ max = lep.getVerticalRange().getUpperBound();
+ }
+ }
+
+ return max;
+ }
+
+ private int getSpecifiedMaxTimeBounds(int minTimeBounds) {
+ List<Lifeline> allLifelines = sequenceDiagram.getAllLifelines();
+ int timeBounds = LayoutConstants.LIFELINES_MIN_Y;
+
+ for (Lifeline lep : allLifelines) {
+ DDiagramElement dde = (DDiagramElement) lep.getNotationNode().getElement();
+ if (dde instanceof DNode && Lifeline.viewpointElementPredicate().apply(dde)) {
+ DNode node = (DNode) dde;
+ int specifiedVSize = getSpecifiedVSize(node);
+ int endOfLifeVsize = getSpecifiedEndOfLifeVSize(node);
+ timeBounds = Math.max(LayoutConstants.LIFELINES_MIN_Y, minTimeBounds + specifiedVSize - endOfLifeVsize / 2);
+ }
+ }
+
+ return timeBounds;
+ }
+
+ private int getSpecifiedEndOfLifeVSize(DNode node) {
+ int endOfLifeVsize = 0;
+
+ List<DNode> endOfLifes = Lists.newArrayList(Iterables.filter(node.getOwnedBorderedNodes(), new Predicate<DNode>() {
+ public boolean apply(DNode input) {
+ return input.isVisible() && EndOfLife.viewpointElementPredicate().apply(input);
+ }
+ }));
+
+ if (!endOfLifes.isEmpty()) {
+ endOfLifeVsize = getSpecifiedVSize(endOfLifes.iterator().next());
+ }
+ return endOfLifeVsize;
+ }
+
+ /**
+ * Return the specified size of the given node.
+ *
+ * @param node
+ * the given node.
+ * @return the specified height of a {@link DNode}.
+ */
+ protected int getSpecifiedVSize(DNode node) {
+ return new DNodeQuery(node).getDefaultDimension().height;
+ }
+
+ private int getMinTimeBounds() {
+ int min = 2 * LayoutConstants.LIFELINES_START_Y;
+ Iterable<Lifeline> lifelinesWithoutCreation = getLifeLinesWithoutCreation();
+
+ // Avoid to handle lifelines to move up for min computation.
+ Predicate<Lifeline> isMinRangeCandidate = new Predicate<Lifeline>() {
+ public boolean apply(Lifeline input) {
+ InstanceRole irep = input.getInstanceRole();
+ if (irep != null) {
+ return irep.getBounds().getLocation().y <= LayoutConstants.LIFELINES_START_Y;
+ }
+ return false;
+ }
+ };
+
+ Collection<Lifeline> lifelinesToConsider = Lists.newArrayList(Iterables.filter(lifelinesWithoutCreation, isMinRangeCandidate));
+ if (!lifelinesToConsider.isEmpty()) {
+ Lifeline lep = heightOrdering.max(lifelinesToConsider);
+ min = LayoutConstants.LIFELINES_START_Y + instanceRoleHeight.apply(lep);
+ }
+ return min;
+ }
+
+ /**
+ * Get the middle height of the given message's targeted figure.
+ *
+ * @param mover
+ * the given message.
+ * @return the middle height.
+ */
+ protected int getTargetFigureMidHeight(Message mover) {
+ int midHeight = 0;
+ if (mover != null && mover.getTargetElement() != null) {
+ midHeight = mover.getTargetElement().getBounds().height / 2;
+ }
+ return midHeight;
+ }
+
+ /**
+ * Increase the time range to the given upperBound. If the current upper
+ * bounds is bigger than the parameter, it does nothing.
+ *
+ * @param upperBound
+ * the new minimum upperBound.
+ */
+ protected void updateTimerange(int upperBound) {
+ if (upperBound > timeRange.getUpperBound()) {
+ timeRange = new Range(timeRange.getLowerBound(), upperBound);
+ }
+ }
+
+ /**
+ * Return the minimum valid lower start time on the {@link Lifeline} of the
+ * given {@link InstanceRole}.
+ *
+ * @param irep
+ * the current {@link InstanceRole}.
+ * @return the lifeline minimum valid lower bound.
+ */
+ protected int getLifelineMinLowerBound(final InstanceRole irep) {
+ int vGap = LayoutConstants.LIFELINES_START_Y;
+ vGap += irep.getBounds().height;
+ return vGap;
+ }
+
+ /**
+ * Register event old and init context (ends, old layout data, previous
+ * bounds flag, creators, destructors, ...).
+ */
+ protected void registerEventEnds() {
+ for (EventEnd end : Lists.newArrayList(semanticOrdering)) {
+ registerEventEnd(end);
+ }
+ Collections.sort(flaggedEnds, Ordering.natural().onResultOf(eventEndOldFlaggedPosition));
+ }
+
+ private void registerEventEnd(EventEnd end) {
+ Collection<EObject> semanticEvents = EventEndHelper.getSemanticEvents(end);
+ Collection<ISequenceEvent> eventParts = Sets.newLinkedHashSet();
+ for (EObject semanticEvent : semanticEvents) {
+ eventParts.addAll(ISequenceElementAccessor.getEventsForSemanticElement(sequenceDiagram, semanticEvent));
+ }
+
+ // ISequenceEvent has not been created
+ if (eventParts.isEmpty()) {
+ Collection<DDiagramElement> ddes = Sets.newLinkedHashSet();
+ for (EObject semanticEvent : semanticEvents) {
+ ddes.addAll(ISequenceElementAccessor.getDiagramElementsForSemanticElement(sequenceDiagram, semanticEvent));
+ }
+
+ // No ISequenceEvent has been created but DDiagramElement exists,
+ // gmf refresh did not occurs, abort
+ // current layout.
+ if (!ddes.isEmpty()) {
+ semanticOrdering.clear();
+ graphicalOrdering.clear();
+ }
+ }
+
+ boolean flagged = false;
+ boolean toolCreated = false;
+ boolean toolSemanticCreated = false;
+ boolean lost = false;
+ for (ISequenceEvent ise : eventParts) {
+ Range oldData = getOldLayoutData(ise);
+ oldLayoutData.put(ise, oldData);
+ endToISequencEvents.put(end, ise);
+ iSequenceEventsToEventEnds.put(ise, end);
+
+ ISequenceElementQuery query = new ISequenceElementQuery(ise);
+ if (query.hasAbsoluteBoundsFlag()) {
+ Rectangle flaggedAbsoluteBounds = query.getFlaggedAbsoluteBounds();
+ if (LayoutConstants.TOOL_CREATION_FLAG.equals(flaggedAbsoluteBounds)) {
+ toolCreated = true;
+ } else if (LayoutConstants.TOOL_CREATION_FLAG_FROM_SEMANTIC.equals(flaggedAbsoluteBounds)) {
+ toolSemanticCreated = true;
+ } else {
+ if (flaggedAbsoluteBounds.height == -1) {
+ // Correct auto-size
+ flaggedAbsoluteBounds.height = 0;
+ }
+ oldFlaggedLayoutData.put(ise, flaggedAbsoluteBounds);
+ flagged = true;
+ }
+ }
+
+ if (ise instanceof Message) {
+ Message smep = (Message) ise;
+ ISequenceNode targetElement = smep.getTargetElement();
+ if (targetElement instanceof InstanceRole) {
+ creators.put(end, smep);
+ } else if (targetElement instanceof EndOfLife) {
+ destructors.put(end, smep);
+ } else if (targetElement instanceof LostMessageEnd) {
+ lost = true;
+ losts.put(end, (LostMessageEnd) targetElement);
+ }
+
+ ISequenceNode sourceElement = smep.getSourceElement();
+ if (sourceElement instanceof LostMessageEnd) {
+ lost = true;
+ losts.put(end, (LostMessageEnd) sourceElement);
+ }
+ }
+ }
+
+ if (flagged && !toolCreated) {
+ flaggedEnds.add(end);
+ } else if (isSafeToolCreation(end)) {
+ if (toolCreated) {
+ toolCreatedEnds.add(end);
+ } else if (toolSemanticCreated && ((end instanceof SingleEventEnd && ((SingleEventEnd) end).isStart()) || lost)) {
+ toolCreatedEnds.add(end);
+ }
+ }
+ }
+
+ private boolean isSafeToolCreation(EventEnd end) {
+ boolean safe = !(end instanceof CompoundEventEnd);
+ safe = safe || EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(end);
+ for (Message msg : Iterables.filter(endToISequencEvents.get(end), Message.class)) {
+ safe = safe || msg.getSourceElement() instanceof LostMessageEnd || msg.getTargetElement() instanceof LostMessageEnd;
+ }
+
+ return safe;
+ }
+
+ /**
+ * Get the common {@link ISequenceEvent} between the given ends.
+ *
+ * @param end1
+ * a first {@link EventEnd}
+ * @param end2
+ * a second {@link EventEnd}
+ * @return the common events between given ends
+ */
+ protected Collection<ISequenceEvent> getCommonISequenceEvent(EventEnd end1, EventEnd end2) {
+ if (end1 == null || end2 == null) {
+ return Collections.<ISequenceEvent> emptyList();
+ }
+ Collection<ISequenceEvent> ises1 = endToISequencEvents.get(end1);
+ Collection<ISequenceEvent> ises2 = endToISequencEvents.get(end2);
+ Collection<ISequenceEvent> commonIses = Lists.newArrayList(ises2);
+ Iterables.retainAll(commonIses, ises1);
+ return commonIses;
+ }
+
+ @Override
+ protected Function<EventEnd, Integer> getOldPosition() {
+ return eventEndOldPosition;
+ }
+
+ @Override
+ protected Function<EventEnd, Integer> getOldFlaggedPosition() {
+ return eventEndOldFlaggedPosition;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/SequenceDDiagramSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/SequenceDDiagramSpec.java
new file mode 100644
index 0000000000..568fc955cc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/SequenceDDiagramSpec.java
@@ -0,0 +1,286 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreEList;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DRepresentationElement;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.business.api.dialect.DialectManager;
+import org.eclipse.sirius.business.internal.metamodel.helper.DSemanticDiagramHelper;
+import org.eclipse.sirius.business.internal.metamodel.operations.DDiagramSpecOperations;
+import org.eclipse.sirius.business.internal.query.DDiagramInternalQuery;
+import org.eclipse.sirius.business.internal.query.DModelElementInternalQuery;
+import org.eclipse.sirius.description.ContainerMapping;
+import org.eclipse.sirius.description.DAnnotation;
+import org.eclipse.sirius.description.DragAndDropTargetDescription;
+import org.eclipse.sirius.description.EdgeMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.description.concern.ConcernDescription;
+import org.eclipse.sirius.description.filter.FilterDescription;
+import org.eclipse.sirius.diagram.sequence.impl.SequenceDDiagramImpl;
+
+/**
+ * Implementation of <code>SequenceDDiagram</code>.
+ *
+ * @author pcdavid
+ */
+public class SequenceDDiagramSpec extends SequenceDDiagramImpl {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DRepresentationImpl#getOwnedRepresentationElements()
+ */
+ @Override
+ public EList<DRepresentationElement> getOwnedRepresentationElements() {
+ final Collection<DDiagramElement> result = getOwnedDiagramElements();
+ return new EcoreEList.UnmodifiableEList<DRepresentationElement>(eInternalContainer(), SiriusPackage.eINSTANCE.getDRepresentation_OwnedRepresentationElements(), result.size(),
+ result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DRepresentationImpl#getRepresentationElements()
+ */
+ @Override
+ public EList<DRepresentationElement> getRepresentationElements() {
+ final Collection<DDiagramElement> result = getDiagramElements();
+ return new EcoreEList.UnmodifiableEList<DRepresentationElement>(eInternalContainer(), SiriusPackage.eINSTANCE.getDRepresentation_RepresentationElements(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getDiagramElements()
+ */
+ @Override
+ public EList<DDiagramElement> getDiagramElements() {
+ final Collection<DDiagramElement> result = new DDiagramInternalQuery(this).getDiagramElements();
+ return new EcoreEList.UnmodifiableEList<DDiagramElement>(eInternalContainer(), SiriusPackage.eINSTANCE.getDDiagram_DiagramElements(), result.size(), result.toArray());
+ }
+
+ /**
+ * Create the contents of the viewpoint.
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#createContents()
+ */
+ @Override
+ public void createContents() {
+ refresh();
+ }
+
+ /**
+ * Create the contents of the viewpoint with the specified root element.
+ *
+ * @param rootElement
+ * the root element.
+ * @see org.eclipse.sirius.impl.DDiagramImpl#createContents(org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public void createContents(final EObject rootElement) {
+ refresh();
+ }
+
+ /**
+ * Update the content of the viewpoint.
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#updateContent()
+ */
+ @Override
+ public void updateContent() {
+ refresh();
+ }
+
+ /**
+ * Clean the viewpoint, delete all elements that are obsolete.
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#clean()
+ */
+ @Override
+ public void clean() {
+ DSemanticDiagramHelper.clean(this);
+ }
+
+ /**
+ * Refresh the viewpoint.
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#refresh()
+ */
+ @Override
+ public void refresh() {
+ DialectManager.INSTANCE.refresh(this, new NullProgressMonitor());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DSemanticDiagramImpl#getRootContent()
+ */
+ @Override
+ public EObject getRootContent() {
+ return DSemanticDiagramHelper.getRootContent(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DRepresentationImpl#getDAnnotation(String)
+ */
+ @Override
+ public DAnnotation getDAnnotation(String source) {
+ return new DModelElementInternalQuery(this).getDAnnotation(source);
+ }
+
+ /*
+ * Behavior inherited from DDiagramSpec
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getEdges()
+ */
+ @Override
+ public EList<DEdge> getEdges() {
+ final Collection<DEdge> result = new DDiagramInternalQuery(this).getEdges();
+ return new EcoreEList.UnmodifiableEList<DEdge>(eInternalContainer(), SiriusPackage.eINSTANCE.getDDiagram_Edges(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getNodes()
+ */
+ @Override
+ public EList<DNode> getNodes() {
+ final Collection<DNode> result = new DDiagramInternalQuery(this).getNodes();
+ return new EcoreEList.UnmodifiableEList<DNode>(eInternalContainer(), SiriusPackage.eINSTANCE.getDDiagram_Nodes(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getNodeListElements()
+ */
+ @Override
+ public EList<DNodeListElement> getNodeListElements() {
+ final Collection<DNodeListElement> result = new DDiagramInternalQuery(this).getNodeListElements();
+ return new EcoreEList.UnmodifiableEList<DNodeListElement>(eInternalContainer(), SiriusPackage.eINSTANCE.getDDiagram_NodeListElements(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getContainers()
+ */
+ @Override
+ public EList<DDiagramElementContainer> getContainers() {
+ final Collection<DDiagramElementContainer> result = new DDiagramInternalQuery(this).getContainers();
+ return new EcoreEList.UnmodifiableEList<DDiagramElementContainer>(eInternalContainer(), SiriusPackage.eINSTANCE.getDDiagram_Containers(), result.size(), result.toArray());
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getNodesFromMapping(org.eclipse.sirius.description.NodeMapping)
+ */
+ @Override
+ public EList<DNode> getNodesFromMapping(final NodeMapping mapping) {
+ return DDiagramSpecOperations.getNodesFromMapping(this, mapping);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getEdgesFromMapping(org.eclipse.sirius.description.EdgeMapping)
+ */
+ @Override
+ public EList<DEdge> getEdgesFromMapping(final EdgeMapping mapping) {
+ return DDiagramSpecOperations.getEdgesFromMapping(this, mapping);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getContainersFromMapping(org.eclipse.sirius.description.ContainerMapping)
+ */
+ @Override
+ public EList<DDiagramElementContainer> getContainersFromMapping(final ContainerMapping mapping) {
+ return DDiagramSpecOperations.getContainersFromMapping(this, mapping);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#validate()
+ */
+ @Override
+ public boolean validate() {
+ return DDiagramSpecOperations.validate(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getAllFilters()
+ */
+ @Override
+ public EList<FilterDescription> getAllFilters() {
+ final Collection<FilterDescription> result = new DDiagramInternalQuery(this).getAllFilters();
+ return new EcoreEList.UnmodifiableEList<FilterDescription>(eInternalContainer(), SiriusPackage.eINSTANCE.getDDiagram_AllFilters(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#setCurrentConcern(org.eclipse.sirius.description.concern.ConcernDescription)
+ */
+ @Override
+ public void setCurrentConcern(final ConcernDescription newCurrentConcern) {
+ super.setCurrentConcern(newCurrentConcern);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#getDragAndDropDescription()
+ */
+ @Override
+ public DragAndDropTargetDescription getDragAndDropDescription() {
+ return new DDiagramInternalQuery(this).getDragAndDropDescription();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.impl.DDiagramImpl#findSiriusElements(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EClass)
+ */
+ @Override
+ public EList<DDiagramElement> findDiagramElements(final EObject semanticElement, final EClass type) {
+ return DDiagramSpecOperations.findDiagramElements(this, semanticElement, type);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/BasicMessageMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/BasicMessageMappingSpec.java
new file mode 100644
index 0000000000..205897c7db
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/BasicMessageMappingSpec.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.EdgeStyle;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.EdgeMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.BasicMessageMappingImpl;
+
+/**
+ * Implementation of <code>BasicMessageMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class BasicMessageMappingSpec extends BasicMessageMappingImpl {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject semanticTarget) {
+ return createEdge(source, target, null, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject container, final EObject semanticTarget) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new EdgeMappingHelper(interpreter).createEdge(this, source, target, container, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getBestStyle(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public EdgeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (EdgeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#updateEdge(org.eclipse.sirius.DEdge)
+ */
+ @Override
+ public void updateEdge(final DEdge dEdge) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(dEdge);
+ new EdgeMappingHelper(interpreter).updateEdge(this, dEdge);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeTargetCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeTargetCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeTargetCandidates(this, semanticOrigin, diagram);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeSourceCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeSourceCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeSourceCandidates(this, semanticOrigin, diagram);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#checkPrecondition(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#getAllMappings()
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return new BasicEList.UnmodifiableEList<DiagramElementMapping>(0, new Object[0]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#isFrom(org.eclipse.sirius.DMappingBased)
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + " " + getName();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CombinedFragmentMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CombinedFragmentMappingSpec.java
new file mode 100644
index 0000000000..f7593f0e36
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CombinedFragmentMappingSpec.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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreEList;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.ContainerStyle;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.IContainerMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.ContainerMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.ContainerMapping;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.CombinedFragmentMappingImpl;
+
+/**
+ * Implementation of CombinedFragmentMapping.
+ *
+ * @author pcdavid
+ */
+public class CombinedFragmentMappingSpec extends CombinedFragmentMappingImpl implements IContainerMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewContainerDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewContainerDone() {
+ return viewContainerDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllNodeMappings() {
+ final Collection<NodeMapping> result = ContainerMappingHelper.getAllNodeMappings(this);
+ return new EcoreEList.UnmodifiableEList<NodeMapping>(eInternalContainer(), DescriptionPackage.eINSTANCE.getContainerMapping_AllNodeMappings(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<ContainerMapping> getAllContainerMappings() {
+ final Collection<ContainerMapping> result = ContainerMappingHelper.getAllContainerMappings(this);
+ return new EcoreEList.UnmodifiableEList<ContainerMapping>(eInternalContainer(), DescriptionPackage.eINSTANCE.getContainerMapping_AllContainerMappings(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return ContainerMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ ContainerMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return ContainerMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DDiagramElementContainer createContainer(final EObject modelElement, final EObject container, final DDiagram viewPoint) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new ContainerMappingHelper(interpreter).createContainer(this, modelElement, container, viewPoint);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateContainer(final DDiagramElementContainer container) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ new ContainerMappingHelper(interpreter).updateContainer(this, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ ContainerMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ContainerStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (ContainerStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(EObject modelElement, DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ Collection filterSemantic, DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return ContainerMappingHelper.getAllMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> getDNodesDone() {
+ return ContainerMappingHelper.getDNodesDone(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CreationMessageMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CreationMessageMappingSpec.java
new file mode 100644
index 0000000000..503ac9cb37
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/CreationMessageMappingSpec.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.EdgeStyle;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.EdgeMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.CreationMessageMappingImpl;
+
+/**
+ * Implementation of <code>CreationMessageMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class CreationMessageMappingSpec extends CreationMessageMappingImpl {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject semanticTarget) {
+ return createEdge(source, target, null, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject container, final EObject semanticTarget) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new EdgeMappingHelper(interpreter).createEdge(this, source, target, container, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getBestStyle(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public EdgeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (EdgeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#updateEdge(org.eclipse.sirius.DEdge)
+ */
+ @Override
+ public void updateEdge(final DEdge dEdge) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(dEdge);
+ new EdgeMappingHelper(interpreter).updateEdge(this, dEdge);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeTargetCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeTargetCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeTargetCandidates(this, semanticOrigin, diagram);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeSourceCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeSourceCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeSourceCandidates(this, semanticOrigin, diagram);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#checkPrecondition(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#getAllMappings()
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return new BasicEList.UnmodifiableEList<DiagramElementMapping>(0, new Object[0]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#isFrom(org.eclipse.sirius.DMappingBased)
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + " " + getName();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/DestructionMessageMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/DestructionMessageMappingSpec.java
new file mode 100644
index 0000000000..0a6ee8faa5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/DestructionMessageMappingSpec.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.EdgeStyle;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.EdgeMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.DestructionMessageMappingImpl;
+
+/**
+ * Implementation of <code>DestructionMessageMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class DestructionMessageMappingSpec extends DestructionMessageMappingImpl {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject semanticTarget) {
+ return createEdge(source, target, null, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject container, final EObject semanticTarget) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new EdgeMappingHelper(interpreter).createEdge(this, source, target, container, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getBestStyle(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public EdgeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (EdgeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#updateEdge(org.eclipse.sirius.DEdge)
+ */
+ @Override
+ public void updateEdge(final DEdge dEdge) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(dEdge);
+ new EdgeMappingHelper(interpreter).updateEdge(this, dEdge);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeTargetCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeTargetCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeTargetCandidates(this, semanticOrigin, diagram);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeSourceCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeSourceCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeSourceCandidates(this, semanticOrigin, diagram);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#checkPrecondition(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#getAllMappings()
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return new BasicEList.UnmodifiableEList<DiagramElementMapping>(0, new Object[0]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#isFrom(org.eclipse.sirius.DMappingBased)
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + " " + getName();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/EndOfLifeMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/EndOfLifeMappingSpec.java
new file mode 100644
index 0000000000..80d0d4d325
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/EndOfLifeMappingSpec.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.BasicEList.UnmodifiableEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.NodeStyle;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.INodeMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.NodeMappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.EndOfLifeMappingImpl;
+
+/**
+ * Implementation of <code>EndOfLifeMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class EndOfLifeMappingSpec extends EndOfLifeMappingImpl implements INodeMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewNodesDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewNodesDone() {
+ return viewNodesDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNode createNode(final EObject modelElement, final EObject container, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createNode(this, modelElement, container, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateNode(final DNode node) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(node);
+ new NodeMappingHelper(interpreter).updateNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NodeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (NodeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNodeListElement createListElement(final EObject modelElement, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createListElement(this, modelElement, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateListElement(final DNodeListElement listElement) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(listElement);
+ new NodeMappingHelper(interpreter).updateListElement(this, listElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ NodeMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return NodeMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(final EObject modelElement, final DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ final Collection filterSemantic, final DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ final BasicEList<DiagramElementMapping> allMappings = new BasicEList<DiagramElementMapping>();
+ allMappings.addAll(this.getAllBorderedNodeMappings());
+ return new UnmodifiableEList<DiagramElementMapping>(allMappings.size(), allMappings.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ NodeMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ExecutionMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ExecutionMappingSpec.java
new file mode 100644
index 0000000000..876d42f4f6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ExecutionMappingSpec.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.BasicEList.UnmodifiableEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.NodeStyle;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.INodeMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.NodeMappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.ExecutionMappingImpl;
+
+/**
+ * Implementation of <code>ExecutionMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class ExecutionMappingSpec extends ExecutionMappingImpl implements INodeMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewNodesDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewNodesDone() {
+ return viewNodesDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNode createNode(final EObject modelElement, final EObject container, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createNode(this, modelElement, container, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateNode(final DNode node) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(node);
+ new NodeMappingHelper(interpreter).updateNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NodeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (NodeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNodeListElement createListElement(final EObject modelElement, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createListElement(this, modelElement, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateListElement(final DNodeListElement listElement) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(listElement);
+ new NodeMappingHelper(interpreter).updateListElement(this, listElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ NodeMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return NodeMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(final EObject modelElement, final DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ final Collection filterSemantic, final DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ final BasicEList<DiagramElementMapping> allMappings = new BasicEList<DiagramElementMapping>();
+ allMappings.addAll(this.getAllBorderedNodeMappings());
+ return new UnmodifiableEList<DiagramElementMapping>(allMappings.size(), allMappings.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ NodeMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InstanceRoleMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InstanceRoleMappingSpec.java
new file mode 100644
index 0000000000..98aa2dfa5b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InstanceRoleMappingSpec.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.BasicEList.UnmodifiableEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.NodeStyle;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.INodeMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.NodeMappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.InstanceRoleMappingImpl;
+
+/**
+ * Implementation of <code>InstanceRoleMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class InstanceRoleMappingSpec extends InstanceRoleMappingImpl implements INodeMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewNodesDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewNodesDone() {
+ return viewNodesDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNode createNode(final EObject modelElement, final EObject container, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createNode(this, modelElement, container, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateNode(final DNode node) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(node);
+ new NodeMappingHelper(interpreter).updateNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NodeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (NodeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNodeListElement createListElement(final EObject modelElement, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createListElement(this, modelElement, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateListElement(final DNodeListElement listElement) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(listElement);
+ new NodeMappingHelper(interpreter).updateListElement(this, listElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ NodeMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return NodeMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(final EObject modelElement, final DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ final Collection filterSemantic, final DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ final BasicEList<DiagramElementMapping> allMappings = new BasicEList<DiagramElementMapping>();
+ allMappings.addAll(this.getAllBorderedNodeMappings());
+ return new UnmodifiableEList<DiagramElementMapping>(allMappings.size(), allMappings.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ NodeMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InteractionUseMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InteractionUseMappingSpec.java
new file mode 100644
index 0000000000..f9f38ccb74
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/InteractionUseMappingSpec.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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreEList;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.ContainerStyle;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.IContainerMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.ContainerMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.ContainerMapping;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.InteractionUseMappingImpl;
+
+/**
+ * Implementation of InteractionUseMapping.
+ *
+ * @author pcdavid
+ */
+public class InteractionUseMappingSpec extends InteractionUseMappingImpl implements IContainerMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewContainerDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewContainerDone() {
+ return viewContainerDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllNodeMappings() {
+ final Collection<NodeMapping> result = ContainerMappingHelper.getAllNodeMappings(this);
+ return new EcoreEList.UnmodifiableEList<NodeMapping>(eInternalContainer(), DescriptionPackage.eINSTANCE.getContainerMapping_AllNodeMappings(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<ContainerMapping> getAllContainerMappings() {
+ final Collection<ContainerMapping> result = ContainerMappingHelper.getAllContainerMappings(this);
+ return new EcoreEList.UnmodifiableEList<ContainerMapping>(eInternalContainer(), DescriptionPackage.eINSTANCE.getContainerMapping_AllContainerMappings(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return ContainerMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ ContainerMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return ContainerMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DDiagramElementContainer createContainer(final EObject modelElement, final EObject container, final DDiagram viewPoint) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new ContainerMappingHelper(interpreter).createContainer(this, modelElement, container, viewPoint);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateContainer(final DDiagramElementContainer container) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ new ContainerMappingHelper(interpreter).updateContainer(this, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ ContainerMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ContainerStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (ContainerStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(EObject modelElement, DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ Collection filterSemantic, DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return ContainerMappingHelper.getAllMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> getDNodesDone() {
+ return ContainerMappingHelper.getDNodesDone(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ObservationPointMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ObservationPointMappingSpec.java
new file mode 100644
index 0000000000..92c5386cc3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ObservationPointMappingSpec.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.BasicEList.UnmodifiableEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.NodeStyle;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.INodeMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.NodeMappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.ObservationPointMappingImpl;
+
+/**
+ * Implementation of <code>ObservationPointMapping</code>.
+ *
+ * @author mporhel
+ */
+public class ObservationPointMappingSpec extends ObservationPointMappingImpl implements INodeMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewNodesDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewNodesDone() {
+ return viewNodesDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNode createNode(final EObject modelElement, final EObject container, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createNode(this, modelElement, container, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateNode(final DNode node) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(node);
+ new NodeMappingHelper(interpreter).updateNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NodeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (NodeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNodeListElement createListElement(final EObject modelElement, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createListElement(this, modelElement, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateListElement(final DNodeListElement listElement) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(listElement);
+ new NodeMappingHelper(interpreter).updateListElement(this, listElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ NodeMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return NodeMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(final EObject modelElement, final DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ final Collection filterSemantic, final DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ final BasicEList<DiagramElementMapping> allMappings = new BasicEList<DiagramElementMapping>();
+ allMappings.addAll(this.getAllBorderedNodeMappings());
+ return new UnmodifiableEList<DiagramElementMapping>(allMappings.size(), allMappings.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ NodeMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/OperandMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/OperandMappingSpec.java
new file mode 100644
index 0000000000..4533cf835d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/OperandMappingSpec.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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreEList;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.ContainerStyle;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.IContainerMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.ContainerMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.ContainerMapping;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.OperandMappingImpl;
+
+/**
+ * Implementation of OperandMapping.
+ *
+ * @author pcdavid
+ */
+public class OperandMappingSpec extends OperandMappingImpl implements IContainerMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewContainerDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewContainerDone() {
+ return viewContainerDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllNodeMappings() {
+ final Collection<NodeMapping> result = ContainerMappingHelper.getAllNodeMappings(this);
+ return new EcoreEList.UnmodifiableEList<NodeMapping>(eInternalContainer(), DescriptionPackage.eINSTANCE.getContainerMapping_AllNodeMappings(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<ContainerMapping> getAllContainerMappings() {
+ final Collection<ContainerMapping> result = ContainerMappingHelper.getAllContainerMappings(this);
+ return new EcoreEList.UnmodifiableEList<ContainerMapping>(eInternalContainer(), DescriptionPackage.eINSTANCE.getContainerMapping_AllContainerMappings(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return ContainerMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ ContainerMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return ContainerMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DDiagramElementContainer createContainer(final EObject modelElement, final EObject container, final DDiagram viewPoint) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new ContainerMappingHelper(interpreter).createContainer(this, modelElement, container, viewPoint);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateContainer(final DDiagramElementContainer container) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ new ContainerMappingHelper(interpreter).updateContainer(this, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ ContainerMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ContainerStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (ContainerStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(final EObject modelElement, final DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ final Collection filterSemantic, final DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return ContainerMappingHelper.getAllMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> getDNodesDone() {
+ return ContainerMappingHelper.getDNodesDone(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ReturnMessageMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ReturnMessageMappingSpec.java
new file mode 100644
index 0000000000..1c389c3c92
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/ReturnMessageMappingSpec.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.EdgeStyle;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.EdgeMappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.ReturnMessageMappingImpl;
+
+/**
+ * Implementation of <code>ReturnMessageMapping</code>.
+ *
+ * @author pcdavid
+ */
+public class ReturnMessageMappingSpec extends ReturnMessageMappingImpl {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject semanticTarget) {
+ return createEdge(source, target, null, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#createEdge(org.eclipse.sirius.EdgeTarget,
+ * org.eclipse.sirius.EdgeTarget, org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public DEdge createEdge(final EdgeTarget source, final EdgeTarget target, final EObject container, final EObject semanticTarget) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(container);
+ return new EdgeMappingHelper(interpreter).createEdge(this, source, target, container, semanticTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getBestStyle(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public EdgeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (EdgeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#updateEdge(org.eclipse.sirius.DEdge)
+ */
+ @Override
+ public void updateEdge(final DEdge dEdge) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(dEdge);
+ new EdgeMappingHelper(interpreter).updateEdge(this, dEdge);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeTargetCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeTargetCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeTargetCandidates(this, semanticOrigin, diagram);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#getEdgeSourceCandidates(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.sirius.DDiagram)
+ */
+ @Override
+ public EList<EObject> getEdgeSourceCandidates(final EObject semanticOrigin, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semanticOrigin);
+ return new EdgeMappingHelper(interpreter).getEdgeSourceCandidates(this, semanticOrigin, diagram);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#checkPrecondition(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#getAllMappings()
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ return new BasicEList.UnmodifiableEList<DiagramElementMapping>(0, new Object[0]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramElementMappingImpl#isFrom(org.eclipse.sirius.DMappingBased)
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.EdgeMappingImpl#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + " " + getName();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/SequenceDiagramDescriptionSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/SequenceDiagramDescriptionSpec.java
new file mode 100644
index 0000000000..ea69459391
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/SequenceDiagramDescriptionSpec.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.business.internal.metamodel.description;
+
+import java.util.Set;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.util.EcoreEList;
+
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.business.internal.metamodel.helper.ContentHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.DiagramDescriptionHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.LayerHelper;
+import org.eclipse.sirius.description.ContainerMapping;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.description.EdgeMapping;
+import org.eclipse.sirius.description.Layer;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+import org.eclipse.sirius.diagram.sequence.SequenceFactory;
+import org.eclipse.sirius.diagram.sequence.description.impl.SequenceDiagramDescriptionImpl;
+
+/**
+ * Specialized version of <code>SequenceDiagramDescriptionImpl</code>.
+ *
+ * @author pcdavid
+ */
+public class SequenceDiagramDescriptionSpec extends SequenceDiagramDescriptionImpl {
+ /**
+ * {@inheritDoc}
+ *
+ * SequenceDiagramDescription produce <code>SequenceDDiagram</code>s at
+ * runtime.
+ */
+ @Override
+ public DSemanticDiagram createDiagram() {
+ return SequenceFactory.eINSTANCE.createSequenceDDiagram();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllTools()
+ */
+ @Override
+ public EList<AbstractToolDescription> getAllTools() {
+ final Set<AbstractToolDescription> result = DiagramDescriptionHelper.getAllTools(this);
+ return new EcoreEList.UnmodifiableEList<AbstractToolDescription>(eInternalContainer(), DescriptionPackage.eINSTANCE.getDiagramDescription_AllTools(), result.size(), result.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllActivatedTools()
+ */
+ @Override
+ public EList<AbstractToolDescription> getAllActivatedTools() {
+ return new BasicEList<AbstractToolDescription>();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllLayers()
+ */
+ @Override
+ public EList<Layer> getAllLayers() {
+ return LayerHelper.getAllLayers(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllEdgeMappings()
+ */
+ @Override
+ public EList<EdgeMapping> getAllEdgeMappings() {
+ return ContentHelper.getAllEdgeMappings(this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllActivatedEdgeMappings()
+ */
+ @SuppressWarnings("deprecation")
+ @Override
+ public EList<EdgeMapping> getAllActivatedEdgeMappings() {
+ return ContentHelper.getAllActivatedEdgeMappings(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllContainerMappings()
+ */
+ @Override
+ public EList<ContainerMapping> getAllContainerMappings() {
+ return ContentHelper.getAllContainerMappings(this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.description.impl.DiagramDescriptionImpl#getAllNodeMappings()
+ */
+ @Override
+ public EList<NodeMapping> getAllNodeMappings() {
+ return ContentHelper.getAllNodeMappings(this, false);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/StateMappingSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/StateMappingSpec.java
new file mode 100644
index 0000000000..93c0402c63
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/StateMappingSpec.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.BasicEList.UnmodifiableEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.EObjectCouple;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DMappingBased;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.NodeStyle;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.business.internal.metamodel.description.extensions.INodeMappingExt;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.AbstractNodeMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.description.operations.SiriusElementMappingSpecOperations;
+import org.eclipse.sirius.business.internal.metamodel.helper.MappingHelper;
+import org.eclipse.sirius.business.internal.metamodel.helper.NodeMappingHelper;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.NodeMapping;
+import org.eclipse.sirius.diagram.sequence.description.impl.StateMappingImpl;
+
+/**
+ * Implementation of <code>StateMapping</code>.
+ *
+ * @author smonnier
+ */
+public class StateMappingSpec extends StateMappingImpl implements INodeMappingExt {
+
+ private final Map<EObject, EList<DSemanticDecorator>> viewNodesDone = new HashMap<EObject, EList<DSemanticDecorator>>();
+
+ private final Map<EObjectCouple, EList<EObject>> candidatesCache = new WeakHashMap<EObjectCouple, EList<EObject>>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObject, EList<DSemanticDecorator>> getViewNodesDone() {
+ return viewNodesDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<EObjectCouple, EList<EObject>> getCandidatesCache() {
+ return candidatesCache;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getNodesCandidates(final EObject semanticOrigin, final EObject container, final EObject containerView) {
+ return NodeMappingHelper.getNodesCandidates(this, semanticOrigin, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNode createNode(final EObject modelElement, final EObject container, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createNode(this, modelElement, container, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateNode(final DNode node) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(node);
+ new NodeMappingHelper(interpreter).updateNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NodeStyle getBestStyle(final EObject modelElement, final EObject viewVariable, final EObject containerVariable) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return (NodeStyle) new MappingHelper(interpreter).getBestStyle(this, modelElement, viewVariable, containerVariable, new EObjectQuery(containerVariable).getParentDiagram().get());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DNodeListElement createListElement(final EObject modelElement, final DDiagram diagram) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(modelElement);
+ return new NodeMappingHelper(interpreter).createListElement(this, modelElement, diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateListElement(final DNodeListElement listElement) {
+ IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(listElement);
+ new NodeMappingHelper(interpreter).updateListElement(this, listElement);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearDNodesDone() {
+ NodeMappingHelper.clearDNodesDone(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DDiagramElement> findDNodeFromEObject(final EObject object) {
+ return NodeMappingHelper.findDNodeFromEObject(this, object);
+ }
+
+ /*
+ * Here we add the behavior we should inherit from AbstractNodeMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ public void createBorderingNodes(final EObject modelElement, final DDiagramElement vpElement, @SuppressWarnings("rawtypes")
+ final Collection filterSemantic, final DDiagram viewPoint) {
+ AbstractNodeMappingSpecOperations.createBorderingNodes(this, modelElement, vpElement, filterSemantic, viewPoint);
+ }
+
+ /*
+ * Behavior inherited from DiagramElementMapping
+ */
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean checkPrecondition(final EObject modelElement, final EObject container, final EObject containerView) {
+ return SiriusElementMappingSpecOperations.checkPrecondition(this, modelElement, container, containerView);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<DiagramElementMapping> getAllMappings() {
+ final BasicEList<DiagramElementMapping> allMappings = new BasicEList<DiagramElementMapping>();
+ allMappings.addAll(this.getAllBorderedNodeMappings());
+ return new UnmodifiableEList<DiagramElementMapping>(allMappings.size(), allMappings.toArray());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFrom(final DMappingBased element) {
+ return SiriusElementMappingSpecOperations.isFrom(this, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDoneNode(final DSemanticDecorator node) {
+ NodeMappingHelper.addDoneNode(this, node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return new StringBuffer(getClass().getName()).append(" ").append(getName()).toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<NodeMapping> getAllBorderedNodeMappings() {
+ return AbstractNodeMappingSpecOperations.getAllBorderedNodeMappings(this);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/tool/MessageCreationToolSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/tool/MessageCreationToolSpec.java
new file mode 100644
index 0000000000..e816179ca9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/description/tool/MessageCreationToolSpec.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.description.tool;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.description.EdgeMapping;
+import org.eclipse.sirius.diagram.sequence.description.tool.impl.MessageCreationToolImpl;
+import org.eclipse.sirius.tools.api.refresh.BestMappingGetter;
+
+/**
+ * Implementation of <code>MessageCreationTool</code>. Uses the same code as the
+ * generic <code>EdgeCreationDescription</code>.
+ *
+ * @author pcdavid
+ */
+public class MessageCreationToolSpec extends MessageCreationToolImpl {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EdgeMapping getBestMapping(final EdgeTarget source, final EdgeTarget target, final EList<EObject> createdElements) {
+ EdgeMapping edgeMapping = null;
+ if (!getEdgeMappings().isEmpty()) {
+ edgeMapping = getEdgeMappings().get(0);
+ if (!createdElements.isEmpty()) {
+ edgeMapping = new BestMappingGetter(source, target, createdElements.get(0)).getBestEdgeMapping(getEdgeMappings());
+ }
+ }
+ return edgeMapping;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/CompoundEventEndSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/CompoundEventEndSpec.java
new file mode 100644
index 0000000000..f6daff3ec9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/CompoundEventEndSpec.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.ordering;
+
+import java.util.Set;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.impl.CompoundEventEndImpl;
+
+/**
+ * Implementation of <code>CompoundEventEnd</code>.
+ *
+ * @author mporhel
+ */
+public class CompoundEventEndSpec extends CompoundEventEndImpl {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EList<EObject> getSemanticEvents() {
+ EList<EObject> result = new BasicEList<EObject>();
+ Set<EObject> semantics = Sets.newHashSet();
+ for (SingleEventEnd see : getEventEnds()) {
+ semantics.add(see.getSemanticEvent());
+ }
+ result.addAll(semantics);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @not-generated
+ */
+ @Override
+ public boolean equals(Object obj) {
+ boolean areEquals = false;
+ if (this == obj) {
+ areEquals = true;
+ } else if (obj instanceof CompoundEventEnd) {
+ CompoundEventEnd that = (CompoundEventEnd) obj;
+ areEquals = this.getSemanticEnd().equals(that.getSemanticEnd()) && this.getEventEnds().size() == that.getEventEnds().size()
+ && this.getSemanticEvents().containsAll(that.getSemanticEvents());
+ }
+ return areEquals;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @not-generated
+ */
+ @Override
+ public int hashCode() {
+ int subHash = 1;
+ for (EObject obj : this.getSemanticEvents()) {
+ subHash *= obj.hashCode();
+ }
+ return 31 * this.getSemanticEnd().hashCode() * subHash;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/SingleEventEndSpec.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/SingleEventEndSpec.java
new file mode 100644
index 0000000000..f3adfa014a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/metamodel/ordering/SingleEventEndSpec.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.business.internal.metamodel.ordering;
+
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.impl.SingleEventEndImpl;
+
+/**
+ * Customization of the default {@link SingleEventEndImpl} implementation.
+ *
+ * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a>
+ *
+ */
+public class SingleEventEndSpec extends SingleEventEndImpl {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @not-generated
+ */
+ @Override
+ public boolean equals(Object obj) {
+ boolean equals = false;
+ if (this == obj) {
+ equals = true;
+ } else if (obj instanceof SingleEventEnd) {
+ SingleEventEnd that = (SingleEventEnd) obj;
+ equals = this.start == that.isStart() && this.getSemanticEnd().equals(that.getSemanticEnd()) && this.getSemanticEvent().equals(that.getSemanticEvent());
+ }
+ return equals;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @not-generated
+ */
+ @Override
+ public int hashCode() {
+ return 17 * this.getSemanticEnd().hashCode() * this.getSemanticEvent().hashCode();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/EndOfLifeMoveOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/EndOfLifeMoveOperation.java
new file mode 100644
index 0000000000..f620a5f0b5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/EndOfLifeMoveOperation.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.business.internal.operation;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.Lifeline;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * Modifies the vertical range of a lifeline edit part to move the end of life
+ * edit part.
+ *
+ * @author mporhel, smonnier
+ */
+public class EndOfLifeMoveOperation extends AbstractModelChangeOperation<Void> {
+ private final Lifeline lifeline;
+
+ private final int rangeDeltaWidth;
+
+ /**
+ * Constructor.
+ *
+ * @param lifeline
+ * the lifeline whose range to modify.
+ * @param rangeDeltaWidth
+ * the rangeDeltaWidth.
+ */
+ public EndOfLifeMoveOperation(Lifeline lifeline, int rangeDeltaWidth) {
+ super("Move EOL");
+ this.lifeline = Preconditions.checkNotNull(lifeline);
+ this.rangeDeltaWidth = rangeDeltaWidth;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ Range movedRange = Range.verticalRange(lifeline.getProperLogicalBounds());
+ lifeline.setVerticalRange(new Range(movedRange.getLowerBound(), movedRange.getUpperBound() + rangeDeltaWidth));
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/FixGraphicalOrderingOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/FixGraphicalOrderingOperation.java
new file mode 100644
index 0000000000..1bfcfb02ae
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/FixGraphicalOrderingOperation.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEndsOrdering;
+
+/**
+ * An operation to remove the invalid ends from the graphical ordering of a
+ * sequence diagram.
+ *
+ * @author pcdavid
+ */
+public final class FixGraphicalOrderingOperation extends AbstractModelChangeOperation<Void> {
+ private final SequenceDDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the diagram whos graphical ordering to fix.
+ */
+ public FixGraphicalOrderingOperation(SequenceDDiagram diagram) {
+ super("Remove invalid ends from graphical ordering");
+ this.diagram = diagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ EventEndsOrdering graphical = diagram.getGraphicalOrdering();
+ List<EventEnd> invalids = findInvalidEnds(graphical);
+ removeEnds(graphical, invalids);
+ return null;
+ }
+
+ private List<EventEnd> findInvalidEnds(EventEndsOrdering graphical) {
+ List<EventEnd> invalids = Lists.newArrayList();
+ for (EventEnd end : graphical.getEventEnds()) {
+ if (!isValidEnd(end)) {
+ invalids.add(end);
+ }
+ }
+ return invalids;
+ }
+
+ private boolean isValidEnd(EventEnd end) {
+ return end.getSemanticEnd() != null && end.getSemanticEnd().eContainer() != null;
+ }
+
+ private void removeEnds(EventEndsOrdering graphical, List<EventEnd> invalids) {
+ for (EventEnd invalidEnd : invalids) {
+ graphical.getEventEnds().remove(invalidEnd);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ISequenceNodeMoveOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ISequenceNodeMoveOperation.java
new file mode 100644
index 0000000000..f29c1360a0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ISequenceNodeMoveOperation.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.business.internal.operation;
+
+import java.util.Collection;
+
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceNode;
+
+/**
+ * Move an execution, interaction use of combined fragment vertically.
+ *
+ * @author pcdavid
+ */
+public class ISequenceNodeMoveOperation extends AbstractModelChangeOperation<Void> {
+
+ private final Collection<ISequenceNode> seqNodes = Sets.newHashSet();
+
+ private final int logicalShift;
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the sequence node to move.
+ * @param logicalShift
+ * the logical shift.
+ */
+ public ISequenceNodeMoveOperation(ISequenceNode node, int logicalShift) {
+ super("Move sequence node");
+ this.seqNodes.add(Preconditions.checkNotNull(node));
+ this.logicalShift = logicalShift;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param nodes
+ * the sequence nodes to move.
+ * @param logicalShift
+ * the logical shift.
+ */
+ public ISequenceNodeMoveOperation(Collection<ISequenceNode> nodes, int logicalShift) {
+ super("Move sequence node");
+ Preconditions.checkNotNull(nodes);
+ this.seqNodes.addAll(nodes);
+ this.logicalShift = logicalShift;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ for (ISequenceNode seqNode : seqNodes) {
+ Node node = seqNode.getNotationNode();
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Location && logicalShift != 0) {
+ Location location = (Location) layoutConstraint;
+ location.setY(location.getY() + logicalShift);
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/InverseRelativeNodePositionOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/InverseRelativeNodePositionOperation.java
new file mode 100644
index 0000000000..8766654810
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/InverseRelativeNodePositionOperation.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.business.internal.operation;
+
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+
+/**
+ * An operation to inverse the relative position of a node on both axes. This is
+ * used for labels on messages to make sure they are always above the message,
+ * regardless of its direction (left-to-right or right-to-left).
+ *
+ * @author pcdavid, smonnier
+ */
+public class InverseRelativeNodePositionOperation extends AbstractModelChangeOperation<Void> {
+ private final Node node;
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the node whose position to inverse.
+ */
+ public InverseRelativeNodePositionOperation(Node node) {
+ super("Inverse Relative Node Position");
+ this.node = Preconditions.checkNotNull(node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ if (node.getLayoutConstraint() instanceof Location) {
+ Location l = (Location) node.getLayoutConstraint();
+ l.setY(-l.getY());
+ l.setX(-l.getX());
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshGraphicalOrderingOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshGraphicalOrderingOperation.java
new file mode 100644
index 0000000000..590aa0ed67
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshGraphicalOrderingOperation.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Ordering;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+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.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.RefreshOrderingHelper;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEndsOrdering;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+
+/**
+ * An operation to re-compute the graphical ordering in which events appear on a
+ * diagram.
+ *
+ * <pre>
+ * GMF View Model ------> GraphicalMessageOrdering
+ * </pre>
+ *
+ * @author pcdavid, smonnier
+ */
+public class RefreshGraphicalOrderingOperation extends AbstractModelChangeOperation<Void> {
+ private final SequenceDDiagram sequenceDiagram;
+
+ /**
+ * Creates a command which updates the graphical ordering of events store in
+ * the model using the latest available graphical informations.
+ *
+ * @param sequenceDiagram
+ * the diagram whose graphical ordering should be refreshed.
+ */
+ public RefreshGraphicalOrderingOperation(SequenceDiagram sequenceDiagram) {
+ super("Refresh graphical ordering");
+ this.sequenceDiagram = sequenceDiagram.getSequenceDDiagram();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ EventEndsOrdering graphicalOrdering = sequenceDiagram.getGraphicalOrdering();
+ if (graphicalOrdering != null) {
+ refreshGlobalOrdering(graphicalOrdering);
+ }
+ return null;
+ }
+
+ private void refreshGlobalOrdering(EventEndsOrdering graphicalOrdering) {
+ if (graphicalOrdering.eContainer() instanceof SequenceDDiagram) {
+ refreshGlobalOrdering(graphicalOrdering, new CustomVerticalPositionFunction(sequenceDiagram));
+ }
+ }
+
+ /**
+ * Recomputes the graphical ordering of events.
+ *
+ * @param sequenceDiagram
+ * the diagram.
+ *
+ * @param verticalPosition
+ * the function to use to obtain the vertical position of the
+ * event ends.
+ */
+ private void refreshGlobalOrdering(EventEndsOrdering graphicalOrdering, VerticalPositionFunction verticalPosition) {
+ final Map<EventEnd, Integer> positions = new MapMaker().makeComputingMap(verticalPosition);
+ Predicate<EventEnd> isValidEnd = new Predicate<EventEnd>() {
+ public boolean apply(EventEnd input) {
+ Integer pos = positions.get(input);
+ return pos != VerticalPositionFunction.INVALID_POSITION && pos != -VerticalPositionFunction.INVALID_POSITION;
+ }
+ };
+ List<EventEnd> allEnds = Lists.newArrayList(Iterables.filter(RefreshOrderingHelper.getAllEventEnds(sequenceDiagram), isValidEnd));
+ Collections.sort(allEnds, Ordering.natural().onResultOf(Functions.forMap(positions)));
+ RefreshOrderingHelper.updateIfNeeded(graphicalOrdering.getEventEnds(), allEnds);
+ }
+
+ /**
+ * Custom vertical function which do not return the real location of an
+ * event end but allow to correctly order event end from logically
+ * instantaneous ISequenceEvent.
+ *
+ * @author mPorhel
+ */
+ private static class CustomVerticalPositionFunction extends VerticalPositionFunction {
+
+ /**
+ * {@inheritDoc}
+ */
+ public CustomVerticalPositionFunction(SequenceDDiagram diagram) {
+ super(diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Integer apply(EventEnd end) {
+ Integer customPos = super.apply(end);
+ if (customPos != INVALID_POSITION || customPos != -INVALID_POSITION) {
+ /*
+ * Simulates a 10x zoom so that we can adjust the
+ * SingleEventEnds position to get the proper ordering. This
+ * manipulation gives us the right ordering, but the actual
+ * Integer values returned by the function should not be used
+ * for anything else than comparing relative positions.
+ */
+ customPos *= 10;
+
+ if (end instanceof SingleEventEnd) {
+ SingleEventEnd see = (SingleEventEnd) end;
+ if (see.isStart()) {
+ customPos -= 1;
+ } else {
+ customPos += 1;
+ }
+
+ }
+ }
+ return customPos;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshSemanticOrderingsOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshSemanticOrderingsOperation.java
new file mode 100644
index 0000000000..42da3b6ce9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/RefreshSemanticOrderingsOperation.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+
+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.Maps;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerInterpreter;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager;
+import org.eclipse.sirius.description.DiagramDescription;
+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.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.ordering.RefreshOrderingHelper;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.description.SequenceDiagramDescription;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEndsOrdering;
+import org.eclipse.sirius.diagram.sequence.ordering.InstanceRolesOrdering;
+import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
+
+/**
+ * An operation to re-compute the global semantic orderings of events and
+ * instance roles in a sequence diagram according to the user-specified
+ * criteria.
+ *
+ * <pre>
+ * Semantic Model + User-specified Ordering Expression ---> SemanticMessageOrdering
+ * </pre>
+ *
+ * @author pcdavid, smonnier
+ */
+public class RefreshSemanticOrderingsOperation extends AbstractModelChangeOperation<Void> {
+ /**
+ * The name of the variable used to pass event ends to sort to
+ * user-specified expressions.
+ */
+ private static final String EVENT_ENDS_TO_SORT_VARIABLE = "eventEnds";
+
+ private final SequenceDDiagram sequenceDDiagram;
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the diagram whose semantic ordering should be refreshed.
+ */
+ public RefreshSemanticOrderingsOperation(SequenceDDiagram diagram) {
+ super("Refresh semantic ordering");
+ this.sequenceDDiagram = Preconditions.checkNotNull(diagram);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ EventEndsOrdering semanticOrdering = sequenceDDiagram.getSemanticOrdering();
+ if (semanticOrdering != null) {
+ refreshGlobalOrdering(semanticOrdering);
+ }
+
+ InstanceRolesOrdering irSemanticOrdering = sequenceDDiagram.getInstanceRoleSemanticOrdering();
+ if (semanticOrdering != null) {
+ refreshGlobalOrdering(irSemanticOrdering);
+ }
+ return null;
+ }
+
+ /**
+ * Refreshes the semantic ordering of all the events in the diagram.
+ * <p>
+ * {@inheritDoc}
+ */
+ private void refreshGlobalOrdering(EventEndsOrdering semanticOrdering) {
+ Iterable<? extends EventEnd> allEnds = RefreshOrderingHelper.getAllEventEnds(sequenceDDiagram);
+ RefreshOrderingHelper.updateIfNeeded(semanticOrdering.getEventEnds(), computeEventEndsOrdering(semanticOrdering, allEnds));
+ }
+
+ private List<EventEnd> computeEventEndsOrdering(EventEndsOrdering semanticOrdering, Iterable<? extends EventEnd> allEnds) {
+ Map<EObject, EventEnd> index = Maps.newHashMap();
+ for (EventEnd eventEnd : allEnds) {
+ index.put(eventEnd.getSemanticEnd(), eventEnd);
+ }
+
+ Iterable<EObject> semanticEnds = Iterables.transform(allEnds, new Function<EventEnd, EObject>() {
+ public EObject apply(EventEnd from) {
+ return from.getSemanticEnd();
+ }
+ });
+ List<EObject> orderedSemanticEnds = computeOrdering(semanticEnds, DescriptionPackage.eINSTANCE.getSequenceDiagramDescription_EndsOrdering(), true);
+
+ List<EventEnd> result = new ArrayList<EventEnd>();
+ for (EObject semanticEnd : orderedSemanticEnds) {
+ EventEnd ee = index.get(semanticEnd);
+ if (ee != null) {
+ result.add(ee);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Refreshes the semantic ordering of all the instance roles in the diagram.
+ */
+ private void refreshGlobalOrdering(InstanceRolesOrdering semanticOrdering) {
+ Iterable<? extends DNode> allInstanceRoles = Iterables.filter(sequenceDDiagram.getNodes(), InstanceRole.viewpointElementPredicate());
+ RefreshOrderingHelper.updateIfNeeded(semanticOrdering.getSemanticInstanceRoles(), computeInstanceRolesOrdering(semanticOrdering, allInstanceRoles));
+ }
+
+ private List<EObject> computeInstanceRolesOrdering(InstanceRolesOrdering semanticOrdering, Iterable<? extends DNode> allInstanceRoles) {
+ List<EObject> semanticInstanceRoles = Lists.newArrayList();
+ for (DNode node : allInstanceRoles) {
+ semanticInstanceRoles.add(node.getTarget());
+ }
+
+ List<EObject> orderedSemanticEnds = computeOrdering(semanticInstanceRoles, DescriptionPackage.eINSTANCE.getSequenceDiagramDescription_InstanceRolesOrdering(), false);
+ return orderedSemanticEnds;
+ }
+
+ private List<EObject> computeOrdering(Iterable<EObject> semanticEnds, EAttribute expressionAttribute, boolean declareEventEndsVariable) {
+ if (StringUtil.isEmpty((String) getSequenceDescription().eGet(expressionAttribute))) {
+ return Lists.newArrayList(semanticEnds);
+ }
+
+ final IInterpreter interpreter = InterpreterUtil.getInterpreter(sequenceDDiagram);
+ if (declareEventEndsVariable) {
+ interpreter.setVariable(EVENT_ENDS_TO_SORT_VARIABLE, Lists.newArrayList(semanticEnds));
+ }
+
+ try {
+ RuntimeLoggerInterpreter loggerInterpreter = RuntimeLoggerManager.INSTANCE.decorate(interpreter);
+ Collection<EObject> result = loggerInterpreter.evaluateCollection(sequenceDDiagram.getTarget(), getSequenceDescription(), expressionAttribute);
+ return Lists.newArrayList(result);
+ } finally {
+ if (declareEventEndsVariable) {
+ interpreter.unSetVariable(EVENT_ENDS_TO_SORT_VARIABLE);
+ }
+ }
+ }
+
+ private SequenceDiagramDescription getSequenceDescription() {
+ if (sequenceDDiagram != null) {
+ DiagramDescription desc = sequenceDDiagram.getDescription();
+ return SequenceDiagramDescription.class.cast(desc);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ReparentExecutionOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ReparentExecutionOperation.java
new file mode 100644
index 0000000000..21c89a910c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ReparentExecutionOperation.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.AbstractNodeEvent;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+
+/**
+ * Update the structure of DNodes and GMF Nodes to reflect that an execution has
+ * a new parent event.
+ *
+ * @author pcdavid, smonnier, mporhel
+ */
+public class ReparentExecutionOperation extends AbstractModelChangeOperation<Void> {
+ private final AbstractNodeEvent execution;
+
+ private final ISequenceEvent finalParent;
+
+ /**
+ * Constructor.
+ *
+ * @param execution
+ * the execution whose parent changed.
+ * @param finalParent
+ * the new parent event of the execution.
+ */
+ public ReparentExecutionOperation(AbstractNodeEvent execution, ISequenceEvent finalParent) {
+ super("Reparent execution");
+ this.execution = Preconditions.checkNotNull(execution);
+ this.finalParent = Preconditions.checkNotNull(finalParent);
+ Preconditions.checkArgument(execution.getNotationView().getElement() instanceof DNode);
+ Preconditions.checkArgument(finalParent.getNotationView().getElement() instanceof AbstractDNode);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ DNode thisSem = (DNode) execution.getNotationView().getElement();
+ Node thisNode = (Node) execution.getNotationView();
+
+ DNode newSem = (DNode) finalParent.getNotationView().getElement();
+ Node newParentNode = (Node) finalParent.getNotationView();
+
+ // real reconnection ?
+ if (validate(thisSem, thisNode, newSem, newParentNode)) {
+ @SuppressWarnings("unchecked")
+ EList<View> persistedChildren = newParentNode.getPersistedChildren();
+ persistedChildren.add(thisNode);
+ newSem.getOwnedBorderedNodes().add(thisSem);
+ }
+ return null;
+ }
+
+ private boolean validate(DNode thisSem, Node thisNode, DNode newSem, Node newParentNode) {
+ boolean validation = thisSem != null && newSem != null && newParentNode != null;
+ validation = validation && !newSem.equals(thisSem.eContainer()) && !newParentNode.equals(thisNode.eContainer());
+ return validation;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SequenceMessageRangeHelper.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SequenceMessageRangeHelper.java
new file mode 100644
index 0000000000..4db4da2dc6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SequenceMessageRangeHelper.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import com.google.common.collect.Iterables;
+
+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.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * A helper to handle the change of vertical range for sequence messages.
+ *
+ * @author pcdavid
+ */
+public class SequenceMessageRangeHelper {
+ private static final String TOP_CENTER_TERMINAL = "(0.5, 0.0)";
+
+ /**
+ * Sets the range for a normal (non-reflective), horizontal message.
+ *
+ * @param edge
+ * the edge representing the message.
+ * @param range
+ * the final range of the message. In practice it is a range of
+ * width 1 for horizontal messages.
+ * @param sourceTop
+ * the logical vertical position of the top of the source element
+ * of the message.
+ * @param targetTop
+ * the logical vertical position of the top of the target element
+ * of the message.
+ */
+ public void setMessageRangeForNormalMessage(Edge edge, Range range, final int sourceTop, final int targetTop) {
+ resetAnchors(edge);
+
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+
+ int[] sourceX = getSourceX(bendpoints);
+ int[] targetX = getTargetX(bendpoints);
+ assert sourceX != null && sourceX.length == 2;
+ assert targetX != null && targetX.length == 2;
+
+ /*
+ * The vertical offsets from the top of the source/target.
+ */
+ int sourceDeltaY = range.getLowerBound() - sourceTop;
+ int targetDeltaY = range.getLowerBound() - targetTop;
+
+ List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>();
+ newBendpoints.add(new RelativeBendpoint(sourceX[0], sourceDeltaY, targetX[0], targetDeltaY));
+ newBendpoints.add(new RelativeBendpoint(sourceX[1], sourceDeltaY, targetX[1], targetDeltaY));
+
+ bendpoints.setPoints(newBendpoints);
+ }
+
+ /**
+ * Sets the range for a reflective message.
+ *
+ * @param edge
+ * the edge representing the message.
+ * @param range
+ * the final range of the message. In practice it is a range of
+ * width 1 for horizontal messages.
+ * @param sourceTop
+ * the logical vertical position of the top of the source element
+ * of the message.
+ * @param targetTop
+ * the logical vertical position of the top of the target element
+ * of the message.
+ */
+ public void setMessageRangeForMessageToSelf(Edge edge, Range range, final int sourceTop, final int targetTop) {
+ resetAnchors(edge);
+
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+
+ if (bendpoints.getPoints().size() == 2) {
+ List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>();
+ RelativeBendpoint firstRB = (RelativeBendpoint) bendpoints.getPoints().get(0);
+ RelativeBendpoint secondRB = (RelativeBendpoint) bendpoints.getPoints().get(1);
+ newBendpoints.add(firstRB);
+ int hGap = LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_HORIZONTAL_GAP;
+ Option<Message> msg = ISequenceElementAccessor.getMessage(edge);
+ if (msg.some()) {
+ hGap = msg.get().getReflexiveMessageWidth();
+ }
+
+ newBendpoints.add(new RelativeBendpoint(firstRB.getSourceX() + hGap, firstRB.getSourceY(), firstRB.getTargetX() + hGap, firstRB.getTargetY()));
+ newBendpoints.add(new RelativeBendpoint(firstRB.getSourceX() + hGap, secondRB.getSourceY(), firstRB.getTargetX() + hGap, secondRB.getTargetY()));
+ newBendpoints.add(secondRB);
+ bendpoints.setPoints(newBendpoints);
+ }
+
+ int[] sourceX = getSourceX(bendpoints);
+ int[] targetX = getTargetX(bendpoints);
+ assert sourceX != null && sourceX.length == 4;
+ assert targetX != null && targetX.length == 4;
+
+ /*
+ * The vertical offsets of the two first/top bendpoints from the top of
+ * the source/target.
+ */
+ int topSourceDeltaY = range.getLowerBound() - sourceTop;
+ int topTargetDeltaY = range.getLowerBound() - targetTop;
+
+ /*
+ * The vertical offsets of the two last/bottom bendpoints from the top
+ * of the source/target.
+ */
+ int bottomSourceDeltaY = range.getUpperBound() - sourceTop;
+ int bottomTargetDeltaY = range.getUpperBound() - targetTop;
+
+ List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>();
+ newBendpoints.add(new RelativeBendpoint(sourceX[0], topSourceDeltaY, targetX[0], topTargetDeltaY));
+ newBendpoints.add(new RelativeBendpoint(sourceX[1], topSourceDeltaY, targetX[0], topTargetDeltaY));
+ newBendpoints.add(new RelativeBendpoint(sourceX[2], bottomSourceDeltaY, targetX[0], bottomTargetDeltaY));
+ newBendpoints.add(new RelativeBendpoint(sourceX[3], bottomSourceDeltaY, targetX[0], bottomTargetDeltaY));
+
+ bendpoints.setPoints(newBendpoints);
+ }
+
+ private int[] getSourceX(final RelativeBendpoints bendpoints) {
+ int[] sourceXs = new int[bendpoints.getPoints().size()];
+ int i = 0;
+ for (RelativeBendpoint rb : Iterables.filter(bendpoints.getPoints(), RelativeBendpoint.class)) {
+ sourceXs[i] = rb.getSourceX();
+ i += 1;
+ }
+ return sourceXs;
+ }
+
+ private int[] getTargetX(final RelativeBendpoints bendpoints) {
+ int[] targetXs = new int[bendpoints.getPoints().size()];
+ int i = 0;
+ for (RelativeBendpoint rb : Iterables.filter(bendpoints.getPoints(), RelativeBendpoint.class)) {
+ targetXs[i] = rb.getTargetX();
+ i += 1;
+ }
+ return targetXs;
+ }
+
+ /**
+ * Reset the anchors of an edge to a known, easy to handle location: the
+ * center of the top side of the source or target element.
+ */
+ private void resetAnchors(Edge edge) {
+ edge.setSourceAnchor(createCanonicalAnchor());
+ edge.setTargetAnchor(createCanonicalAnchor());
+ }
+
+ private IdentityAnchor createCanonicalAnchor() {
+ IdentityAnchor anchor = NotationFactory.eINSTANCE.createIdentityAnchor();
+ anchor.setId(TOP_CENTER_TERMINAL);
+ return anchor;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetMessageRangeOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetMessageRangeOperation.java
new file mode 100644
index 0000000000..26e4688dbc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetMessageRangeOperation.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Objects;
+
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * An operation to set the vertical range of a sequence message.
+ *
+ * @author pcdavid, smonnier
+ */
+public class SetMessageRangeOperation extends AbstractModelChangeOperation<Void> {
+
+ private static final String LABEL = "Set Sequence Message Vertical Range";
+
+ private Edge message;
+
+ private final Range range;
+
+ private View source;
+
+ private Rectangle sourceBounds;
+
+ private View target;
+
+ private Rectangle targetBounds;
+
+ /**
+ * .
+ *
+ * @param message
+ * .
+ * @param range
+ * .
+ */
+ public SetMessageRangeOperation(Edge message, Range range) {
+ this(message, range, false);
+ }
+
+ /**
+ * .
+ *
+ * @param message
+ * .
+ * @param range
+ * .
+ * @param copyEdge
+ * .
+ */
+ public SetMessageRangeOperation(Edge message, Range range, boolean copyEdge) {
+ super(LABEL);
+ this.message = message;
+ this.range = range;
+ }
+
+ /**
+ * .
+ *
+ * @param src
+ * .
+ * @param srcBounds
+ * .
+ */
+ public void setSource(View src, Rectangle srcBounds) {
+ this.source = src;
+ this.sourceBounds = srcBounds.getCopy();
+ }
+
+ /**
+ * .
+ *
+ * @param tgt
+ * .
+ * @param tgtBounds
+ * .
+ */
+ public void setTarget(View tgt, Rectangle tgtBounds) {
+ this.target = tgt;
+ this.targetBounds = tgtBounds.getCopy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ if (message.getElement() != null && message.getElement().eContainer() != null) {
+ Edge currentMessage = message;
+
+ currentMessage.setSource(source);
+ if (currentMessage.getElement() instanceof DEdge && source.getElement() instanceof EdgeTarget) {
+ ((DEdge) currentMessage.getElement()).setSourceNode((EdgeTarget) source.getElement());
+ }
+ currentMessage.setTarget(target);
+ if (currentMessage.getElement() instanceof DEdge && target.getElement() instanceof EdgeTarget) {
+ ((DEdge) currentMessage.getElement()).setTargetNode((EdgeTarget) target.getElement());
+ }
+
+ int srcTop = sourceBounds.getTop().y;
+ int tgtTop = targetBounds.getTop().y;
+ SequenceMessageRangeHelper helper = new SequenceMessageRangeHelper();
+ if (isMessageToSelf(currentMessage)) {
+ helper.setMessageRangeForMessageToSelf(currentMessage, range, srcTop, tgtTop);
+ } else {
+ helper.setMessageRangeForNormalMessage(currentMessage, range, srcTop, tgtTop);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * FIXME This method should be in an helper class.
+ *
+ * @param msg
+ * an Edge
+ * @return if the edge is reflexive.
+ */
+ private boolean isMessageToSelf(Edge msg) {
+ View src = msg.getSource();
+ View tgt = msg.getTarget();
+ return Objects.equal(src, tgt) || Objects.equal(src.eContainer(), tgt) || Objects.equal(src, tgt.eContainer());
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetVerticalRangeOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetVerticalRangeOperation.java
new file mode 100644
index 0000000000..df61191868
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SetVerticalRangeOperation.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.business.internal.operation;
+
+import com.google.common.base.Preconditions;
+
+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.util.Range;
+
+/**
+ * Modifies the vertical range of an event on a sequence diagram.
+ *
+ * @author pcdavid, smonnier
+ */
+public class SetVerticalRangeOperation extends AbstractModelChangeOperation<Void> {
+ private final ISequenceEvent ise;
+
+ private final Range newRange;
+
+ /**
+ * Constructor.
+ *
+ * @param ise
+ * the event whose range to modify.
+ * @param newRange
+ * the new vertical range for the event.
+ */
+ public SetVerticalRangeOperation(ISequenceEvent ise, Range newRange) {
+ super("Set vertical range");
+ this.ise = Preconditions.checkNotNull(ise);
+ this.newRange = Preconditions.checkNotNull(newRange);
+ Preconditions.checkArgument(!newRange.isEmpty());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ if (ise.getSemanticTargetElement().some()) {
+ ise.setVerticalRange(newRange);
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ShiftDirectSubExecutionsOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ShiftDirectSubExecutionsOperation.java
new file mode 100644
index 0000000000..c4a790e66d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/ShiftDirectSubExecutionsOperation.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+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.util.Range;
+
+/**
+ * This command moves all the direct sub-executions of a given ExecutionEdipart
+ * vertically. It is used when an execution is resized from the top to ensure
+ * the sub-executions stay at the same absolute position instead of moving along
+ * (as they are relative to the top of the parent).
+ *
+ * @author pcdavid, smonnier
+ */
+public class ShiftDirectSubExecutionsOperation extends AbstractModelChangeOperation<Void> {
+ private final int deltaY;
+
+ private final ISequenceEvent parent;
+
+ /**
+ * Constructor.
+ *
+ * @param parent
+ * the execution or lifeline whose direct sub-executions must be
+ * shifted.
+ * @param deltaY
+ * the vertical amount to shift the sub-executions (in logical
+ * space).
+ */
+ public ShiftDirectSubExecutionsOperation(ISequenceEvent parent, int deltaY) {
+ super("Shift sub-executions' positions by " + deltaY);
+ this.parent = Preconditions.checkNotNull(parent);
+ this.deltaY = deltaY;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+
+ for (View view : Iterables.filter(Iterables.filter(parent.getNotationView().getChildren(), View.class), AbstractNodeEvent.notationPredicate())) {
+ Option<AbstractNodeEvent> execution = ISequenceElementAccessor.getAbstractNodeEvent(view);
+ if (execution.some()) {
+ AbstractNodeEvent ise = execution.get();
+ Range rg = ise.getVerticalRange();
+ Range nrg = new Range(rg.getLowerBound() + deltaY, rg.getUpperBound() + deltaY);
+ ise.setVerticalRange(nrg);
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeGraphicalOrderingOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeGraphicalOrderingOperation.java
new file mode 100644
index 0000000000..351e93e864
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeGraphicalOrderingOperation.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+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.layout.SequenceLayout;
+
+/**
+ * Refreshes the graphical locations of the elements in a sequence diagram to
+ * reflect the current semantic ordering. This command assumes that the
+ * {@link org.eclipse.sirius.diagram.sequence.ordering.GraphicalOrdering} and
+ * the {@link org.eclipse.sirius.diagram.sequence.ordering.SemanticOrdering}
+ * are up to date according to the current visual (resp. semantic) order but
+ * that when they do not match, the semantic ordering is the authoritative one
+ * and the graphical ordering should be changed to match it.
+ *
+ * @author pcdavid, smonnier
+ */
+public class SynchronizeGraphicalOrderingOperation extends AbstractModelChangeOperation<Void> {
+
+ private final Diagram sequenceDiagram;
+
+ private final boolean pack;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram to refresh.
+ * @param pack
+ * if <code>true</code> the diagram will be packed
+ */
+ public SynchronizeGraphicalOrderingOperation(Diagram sequenceDiagram, boolean pack) {
+ super("Synchronize graphical ordering");
+ this.sequenceDiagram = Preconditions.checkNotNull(sequenceDiagram);
+ this.pack = pack;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ Preconditions.checkNotNull(sequenceDiagram);
+ SequenceLayout sequenceLayout = new SequenceLayout(sequenceDiagram);
+ Option<SequenceDiagram> sd = sequenceLayout.getSequenceDiagram();
+
+ if (sd.some()) {
+ SequenceDDiagram diagram = (SequenceDDiagram) sd.get().getNotationDiagram().getElement();
+
+ if (diagram != null && (diagram.getGraphicalOrdering().getEventEnds().size() == diagram.getSemanticOrdering().getEventEnds().size())) {
+ boolean verticalLayout = sequenceLayout.verticalLayout(pack);
+ boolean horizontalLayout = sequenceLayout.horizontalLayout(pack);
+ boolean observationLayout = sequenceLayout.observationLayout(pack);
+
+ // Refresh flags when a layout made modifications.
+ if (verticalLayout || horizontalLayout || observationLayout) {
+ sequenceLayout.flagSequenceEvents();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeISequenceEventsSemanticOrderingOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeISequenceEventsSemanticOrderingOperation.java
new file mode 100644
index 0000000000..400a2300a1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeISequenceEventsSemanticOrderingOperation.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Objects;
+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.DDiagramElement;
+import org.eclipse.sirius.business.api.componentization.DiagramComponentizationManager;
+import org.eclipse.sirius.business.api.query.DiagramElementMappingQuery;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+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.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.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.SequenceDiagram;
+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.tool.ToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.description.tool.ReorderTool;
+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.tools.api.command.SiriusCommand;
+
+/**
+ * Refreshes the semantic ordering of a an element of a sequence diagram to
+ * reflect the current graphical ordering. This command assumes that the
+ * <code>GraphicalMessageOrdering</code> and the
+ * <code>SemanticMessageOrdering</code> are up to date according to the current
+ * visual (resp. semantic) order but that when they do not match, the graphical
+ * ordering is the authoritative one and the semantic ordering should be changed
+ * to match it, through the appropriate use of the user-specified
+ * <code>ReorderTool</code>.
+ *
+ * @author pcdavid, smonnier
+ */
+public class SynchronizeISequenceEventsSemanticOrderingOperation extends AbstractModelChangeOperation<Void> {
+ /**
+ * The name of the command.
+ */
+ public static final String COMMAND_NAME = "Synchronize semantic ordering";
+
+ private static final boolean STARTING_END = true;
+
+ private static final boolean FINISHING_END = false;
+
+ private ISequenceEvent event;
+
+ private Set<ISequenceEvent> selection = Sets.newHashSet();
+
+ private final SequenceDDiagram sequenceDiagram;
+
+ private final SequenceDiagram diagram;
+
+ private final Set<ISequenceEvent> reordered = Sets.newHashSet();
+
+ private final Set<ISequenceEvent> allElementsToReorder = Sets.newHashSet();
+
+ /**
+ * Constructor.
+ *
+ * @param event
+ * the event to move to its new location in the semantic order.
+ */
+ public SynchronizeISequenceEventsSemanticOrderingOperation(ISequenceEvent event) {
+ super("Synchronize semantic ordering");
+ this.event = Preconditions.checkNotNull(event);
+ this.diagram = event.getDiagram();
+ this.sequenceDiagram = this.diagram.getSequenceDDiagram();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param event
+ * the event to move to its new location in the semantic order.
+ * @param selection
+ * additional events to reorder
+ */
+ public SynchronizeISequenceEventsSemanticOrderingOperation(ISequenceEvent event, Collection<ISequenceEvent> selection) {
+ this(event);
+ Preconditions.checkNotNull(selection);
+ this.selection.addAll(selection);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ if (event instanceof AbstractNodeEvent && event.getParentEvent() == null) {
+ // The edit-part which requested the synchronize has been removed
+ // from the hierarchy.
+ // Look for its replacement edit part on the same semantic element
+ DDiagramElement dde = (DDiagramElement) event.getNotationView().getElement();
+ Collection<ISequenceEvent> events = ISequenceElementAccessor.getEventsForSemanticElement(diagram, dde.getTarget());
+ if (!events.isEmpty()) {
+ event = events.iterator().next();
+ }
+ }
+
+ Iterables.addAll(allElementsToReorder, new ISequenceEventQuery(event).getAllSequenceEventToMoveWith(selection));
+
+ updateSemanticPositions();
+ return null;
+ }
+
+ private void updateSemanticPositions() {
+ updateSemanticPosition(event);
+ for (ISequenceEvent selected : selection) {
+ updateSemanticPosition(selected);
+ }
+ }
+
+ private void updateSemanticPosition(ISequenceEvent eventToUpdate) {
+ DDiagramElement dde = resolveDiagramElement(eventToUpdate);
+ if (dde == null || reordered.contains(eventToUpdate)) {
+ return;
+ }
+
+ ReorderTool reorderTool = findReorderTool(dde);
+ if (reorderTool == null) {
+ return;
+ }
+
+ EObject semanticElement = dde.getTarget();
+ EList<EventEnd> endsBySemanticOrder = sequenceDiagram.getSemanticOrdering().getEventEnds();
+ EList<EventEnd> endsByGraphicalOrder = sequenceDiagram.getGraphicalOrdering().getEventEnds();
+
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(eventToUpdate);
+ List<EventEnd> compoundEnds = getCompoundEnds(eventToUpdate, ends);
+
+ // Ignore the ends of the descendants: they are treated by recursive
+ // calls.
+ Set<EventEnd> toIgnore = selectEndsToIgnore(eventToUpdate, endsBySemanticOrder, ends, compoundEnds);
+
+ // The semantic ordering contains the state before the move
+ EventEnd startingEndPredecessorBefore = findEndPredecessor(semanticElement, STARTING_END, endsBySemanticOrder, toIgnore);
+ EventEnd finishingEndPredecessorBefore = findEndPredecessor(semanticElement, FINISHING_END, endsBySemanticOrder, toIgnore);
+
+ // The graphical ordering contains the state after
+ EventEnd startingEndPredecessorAfter = findEndPredecessor(semanticElement, STARTING_END, endsByGraphicalOrder, toIgnore);
+ EventEnd finishingEndPredecessorAfter = findEndPredecessor(semanticElement, FINISHING_END, endsByGraphicalOrder, toIgnore);
+
+ // Handle lost messages
+ if (eventToUpdate.isLogicallyInstantaneous() && eventToUpdate instanceof Message && ends.size() == 1 && !Iterables.any(ends, Predicates.instanceOf(CompoundEventEnd.class))) {
+ SingleEventEnd see = (SingleEventEnd) ends.iterator().next();
+ if (see.isStart()) {
+ finishingEndPredecessorBefore = startingEndPredecessorBefore;
+ finishingEndPredecessorAfter = startingEndPredecessorAfter;
+ } else {
+ startingEndPredecessorBefore = finishingEndPredecessorBefore;
+ startingEndPredecessorAfter = finishingEndPredecessorAfter;
+ }
+
+ }
+
+ if (!Objects.equal(startingEndPredecessorBefore, startingEndPredecessorAfter) || !Objects.equal(finishingEndPredecessorBefore, finishingEndPredecessorAfter)
+ || !Iterables.elementsEqual(endsByGraphicalOrder, endsBySemanticOrder)) {
+ applySemanticReordering(semanticElement, startingEndPredecessorAfter, finishingEndPredecessorAfter, reorderTool);
+ applyCompoundReordering(semanticElement, ends, compoundEnds, startingEndPredecessorAfter, finishingEndPredecessorAfter, reorderTool);
+ reordered.add(eventToUpdate);
+
+ new RefreshSemanticOrderingsOperation(sequenceDiagram).execute();
+ // updateLinkedEventsSemanticPositions(eventToUpdate);
+ updateSubEventsSemanticPositions(eventToUpdate);
+ }
+ }
+
+ private DDiagramElement resolveDiagramElement(ISequenceEvent eventToUpdate) {
+ EObject element = eventToUpdate.getNotationView().getElement();
+ if (element instanceof DDiagramElement) {
+ return (DDiagramElement) element;
+ }
+ throw new RuntimeException("Invalid context for ISequenceEvent " + eventToUpdate);
+ }
+
+ private List<EventEnd> getCompoundEnds(ISequenceEvent eventToUpdate, List<EventEnd> ends) {
+ List<ISequenceEvent> compoundEvents = EventEndHelper.getCompoundEvents(eventToUpdate);
+ Predicate<ISequenceEvent> isLogicallyInstantaneous = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ return input.isLogicallyInstantaneous();
+ };
+ };
+ return Lists.newArrayList(Iterables.filter(
+ Iterables.filter(Iterables.concat(Iterables.transform(Iterables.filter(compoundEvents, isLogicallyInstantaneous), EventEndHelper.EVENT_ENDS)),
+ Predicates.instanceOf(SingleEventEnd.class)), Predicates.not(Predicates.in(ends))));
+ }
+
+ private void updateSubEventsSemanticPositions(ISequenceEvent eventToUpdate) {
+ for (ISequenceEvent subEvent : eventToUpdate.getEventsToMoveWith()) {
+ updateSemanticPosition(subEvent);
+ }
+ }
+
+ private void applyCompoundReordering(EObject semanticElement, List<EventEnd> ends, List<EventEnd> compoundEnds, EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor,
+ ReorderTool reorderTool) {
+ if (compoundEnds.isEmpty() || ends.size() != 2) {
+ return;
+ }
+
+ EventEnd startEventEnd = ends.get(0);
+ List<EObject> startSemanticEvents = EventEndHelper.getSemanticEvents(startEventEnd);
+ EventEnd endEventEnd = ends.get(1);
+
+ for (EventEnd ee : compoundEnds) {
+ List<EObject> eeSemElts = EventEndHelper.getSemanticEvents(ee);
+ EventEnd otherEnd = Iterables.any(eeSemElts, Predicates.in(startSemanticEvents)) ? startEventEnd : endEventEnd;
+ EventEnd predecessor = Iterables.any(eeSemElts, Predicates.in(startSemanticEvents)) ? startingEndPredecessor : finishingEndPredecessor;
+
+ for (EObject elt : eeSemElts) {
+ SingleEventEnd singleEventEnd = EventEndHelper.getSingleEventEnd(otherEnd, elt);
+ ISequenceEvent ise = EventEndHelper.findISequenceEvent(singleEventEnd, diagram);
+ if (!singleEventEnd.isStart()) {
+ // SemanticEvent is before otherEnd
+ applySemanticReordering(elt, predecessor, ee, reorderTool);
+ } else {
+ // SemanticEvent is after otherEnd
+ applySemanticReordering(elt, predecessor, otherEnd, reorderTool);
+ }
+ reordered.add(ise);
+ }
+ }
+ }
+
+ private Set<EventEnd> selectEndsToIgnore(ISequenceEvent ise, List<EventEnd> endsBySemanticOrder, final List<EventEnd> iseEnds, final List<EventEnd> compoundEnds) {
+ final Iterable<ISequenceEvent> movedElements = Iterables.filter(allElementsToReorder, Predicates.not(Predicates.in(reordered)));
+ final Set<EObject> semanticLinked = Sets.newHashSet(Iterables.filter(Iterables.transform(movedElements, ISequenceElement.SEMANTIC_TARGET), Predicates.notNull()));
+ final Predicate<EObject> isLinkedSubEventEnd = new Predicate<EObject>() {
+ public boolean apply(EObject input) {
+ return semanticLinked.contains(input);
+ }
+ };
+
+ final Set<EObject> semanticDescendants = Sets.newHashSet(Iterables.filter(Iterables.transform(new ISequenceEventQuery(ise).getAllDescendants(), ISequenceElement.SEMANTIC_TARGET),
+ Predicates.notNull()));
+ final Predicate<EObject> isSemanticSubEventEnd = new Predicate<EObject>() {
+ public boolean apply(EObject input) {
+ return semanticDescendants.contains(input);
+ }
+ };
+
+ Predicate<EventEnd> toIgnore = new Predicate<EventEnd>() {
+ public boolean apply(EventEnd input) {
+ return !iseEnds.contains(input) && (Iterables.any(EventEndHelper.getSemanticEvents(input), Predicates.or(isSemanticSubEventEnd, isLinkedSubEventEnd)) || compoundEnds.contains(input));
+ }
+ };
+ HashSet<EventEnd> newHashSet = Sets.newHashSet(Iterables.filter(endsBySemanticOrder, toIgnore));
+ return newHashSet;
+ }
+
+ private EventEnd findEndPredecessor(EObject semanticElement, boolean startingEnd, List<EventEnd> eventEnds, Set<EventEnd> toIgnore) {
+ EventEnd result = null;
+ for (EventEnd end : Iterables.filter(eventEnds, Predicates.not(Predicates.in(toIgnore)))) {
+ if (isLookedEnd(semanticElement, startingEnd, end)) {
+ break;
+ } else {
+ result = end;
+ }
+ }
+ return result;
+ }
+
+ private boolean isLookedEnd(EObject semanticElement, boolean startingEnd, EventEnd end) {
+ boolean currentMovedEnd = false;
+ List<EObject> semanticEvents = EventEndHelper.getSemanticEvents(end);
+ if (semanticEvents.contains(semanticElement)) {
+ boolean lookedEventEnd = EventEndHelper.getSingleEventEnd(end, semanticElement).isStart() == startingEnd;
+ boolean punctualCompoundEvent = EventEndHelper.PUNCTUAL_COMPOUND_EVENT_END.apply(end);
+ currentMovedEnd = lookedEventEnd || punctualCompoundEvent;
+ }
+ return currentMovedEnd;
+ }
+
+ private void applySemanticReordering(EObject semanticElement, EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor, ReorderTool reorderTool) {
+ SiriusCommand cmd = ToolCommandBuilder.buildReorderCommand(sequenceDiagram, reorderTool, semanticElement, startingEndPredecessor, finishingEndPredecessor);
+ cmd.execute();
+ }
+
+ private ReorderTool findReorderTool(DDiagramElement diagramElement) {
+ if (diagramElement != null) {
+ List<AbstractToolDescription> allTools;
+ Session session = SessionManager.INSTANCE.getSession(diagramElement);
+ if (session != null) {
+ allTools = new DiagramComponentizationManager().getAllTools(session.getSelectedSiriuss(false), sequenceDiagram.getDescription());
+ } else {
+ allTools = sequenceDiagram.getDescription().getAllTools();
+ }
+
+ DiagramElementMapping mappingToCheck = new DiagramElementMappingQuery(diagramElement.getDiagramElementMapping()).getRootMapping();
+
+ // TODO Consider layers activation
+ for (ReorderTool toolDesc : Iterables.filter(allTools, ReorderTool.class)) {
+ if (toolDesc.getMappings().contains(mappingToCheck)) {
+ return toolDesc;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeInstanceRoleSemanticOrderingOperation.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeInstanceRoleSemanticOrderingOperation.java
new file mode 100644
index 0000000000..51b1053e2e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/SynchronizeInstanceRoleSemanticOrderingOperation.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+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.DDiagramElement;
+import org.eclipse.sirius.business.api.componentization.DiagramComponentizationManager;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.description.tool.AbstractToolDescription;
+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.ISequenceElement;
+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.business.internal.tool.ToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.description.tool.InstanceRoleReorderTool;
+import org.eclipse.sirius.tools.api.command.SiriusCommand;
+
+/**
+ * Refreshes the semantic ordering of a an element of a sequence diagram to
+ * reflect the current graphical ordering. This command assumes that the
+ * <code>GraphicalMessageOrdering</code> and the
+ * <code>SemanticMessageOrdering</code> are up to date according to the current
+ * visual (resp. semantic) order but that when they do not match, the graphical
+ * ordering is the authoritative one and the semantic ordering should be changed
+ * to match it, through the appropriate use of the user-specified
+ * <code>ReorderTool</code>.
+ *
+ * @author pcdavid, smonnier
+ */
+public class SynchronizeInstanceRoleSemanticOrderingOperation extends AbstractModelChangeOperation<Void> {
+ /**
+ * The name of the command.
+ */
+ public static final String COMMAND_NAME = "Synchronize semantic ordering";
+
+ private final SequenceDDiagram sequenceDiagram;
+
+ private final SequenceDiagram diagram;
+
+ private final Set<InstanceRole> reordered = Sets.newLinkedHashSet();
+
+ private InstanceRole instanceRole;
+
+ private Set<InstanceRole> selection = Sets.newLinkedHashSet();
+
+ /**
+ * Constructor.
+ *
+ * @param instanceRole
+ * the instance role to move to its new location in the semantic
+ * order.
+ */
+ public SynchronizeInstanceRoleSemanticOrderingOperation(InstanceRole instanceRole) {
+ super(COMMAND_NAME);
+ this.instanceRole = Preconditions.checkNotNull(instanceRole);
+ this.diagram = instanceRole.getDiagram();
+ this.sequenceDiagram = this.diagram.getSequenceDDiagram();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param instanceRole
+ * the instance role to move to its new location in the semantic
+ * order.
+ * @param selection
+ * additional events to reorder
+ */
+ public SynchronizeInstanceRoleSemanticOrderingOperation(InstanceRole instanceRole, Collection<InstanceRole> selection) {
+ this(instanceRole);
+ Preconditions.checkNotNull(selection);
+ this.selection.addAll(selection);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ updateSemanticPositions();
+ return null;
+ }
+
+ private void updateSemanticPositions() {
+ updateSemanticPosition(instanceRole);
+ for (InstanceRole selected : selection) {
+ updateSemanticPosition(selected);
+ }
+ }
+
+ private void updateSemanticPosition(InstanceRole instanceRoleToUpdate) {
+ DDiagramElement dde = resolveDiagramElement(instanceRoleToUpdate);
+ if (dde == null || reordered.contains(instanceRoleToUpdate)) {
+ return;
+ }
+
+ InstanceRoleReorderTool reorderTool = findReorderTool(dde);
+ if (reorderTool == null) {
+ return;
+ }
+
+ EObject semanticElement = dde.getTarget();
+ List<EObject> rolesBySemanticOrder = sequenceDiagram.getInstanceRoleSemanticOrdering().getSemanticInstanceRoles();
+ List<EObject> rolesByGraphicalOrder = getSemanticInstanceRolesByGraphicalOrder();
+
+ // The semantic ordering contains the state before the move
+ EObject predecessorBefore = findEndPredecessor(semanticElement, rolesBySemanticOrder);
+
+ // The graphical ordering contains the state after
+ EObject predecessorAfter = findEndPredecessor(semanticElement, rolesByGraphicalOrder);
+
+ if (!rolesBySemanticOrder.isEmpty() && !Objects.equal(predecessorBefore, predecessorAfter) || !Iterables.elementsEqual(rolesBySemanticOrder, rolesByGraphicalOrder)) {
+ applySemanticReordering(semanticElement, predecessorBefore, predecessorAfter, reorderTool);
+ reordered.add(instanceRoleToUpdate);
+
+ new RefreshSemanticOrderingsOperation(sequenceDiagram).execute();
+ }
+ }
+
+ private List<EObject> getSemanticInstanceRolesByGraphicalOrder() {
+ Iterable<Diagram> diagramViews = Iterables.filter(ISequenceElementAccessor.getViewsForSemanticElement(sequenceDiagram, sequenceDiagram.getTarget()), Diagram.class);
+ if (!Iterables.isEmpty(diagramViews)) {
+ Option<SequenceDiagram> seqDiag = ISequenceElementAccessor.getSequenceDiagram(diagramViews.iterator().next());
+ if (seqDiag.some()) {
+ return Lists.newArrayList(Iterables.transform(seqDiag.get().getSortedInstanceRole(), ISequenceElement.SEMANTIC_TARGET));
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private DDiagramElement resolveDiagramElement(InstanceRole instanceRoleToUpdate) {
+ EObject element = instanceRoleToUpdate.getNotationView().getElement();
+ if (element instanceof DDiagramElement) {
+ return (DDiagramElement) element;
+ }
+ throw new RuntimeException("Invalid context for InstanceRole " + instanceRoleToUpdate);
+ }
+
+ private EObject findEndPredecessor(EObject semanticElement, List<EObject> semanticInstanceRoles) {
+ EObject result = null;
+ for (EObject current : semanticInstanceRoles) {
+ if (semanticElement == current) {
+ break;
+ } else {
+ result = current;
+ }
+ }
+ return result;
+ }
+
+ private void applySemanticReordering(EObject semanticElement, EObject predecessorBefore, EObject predecessorAfter, InstanceRoleReorderTool reorderTool) {
+ SiriusCommand cmd = ToolCommandBuilder.buildInstanceRoleReorderCommand(sequenceDiagram, reorderTool, semanticElement, predecessorBefore, predecessorAfter);
+ cmd.execute();
+ }
+
+ private InstanceRoleReorderTool findReorderTool(DDiagramElement diagramElement) {
+ if (diagramElement != null) {
+ List<AbstractToolDescription> allTools;
+ Session session = SessionManager.INSTANCE.getSession(diagramElement);
+ if (session != null) {
+ allTools = new DiagramComponentizationManager().getAllTools(session.getSelectedSiriuss(false), sequenceDiagram.getDescription());
+ } else {
+ allTools = sequenceDiagram.getDescription().getAllTools();
+ }
+ // TODO Consider layers activation
+ for (InstanceRoleReorderTool toolDesc : Iterables.filter(allTools, InstanceRoleReorderTool.class)) {
+ if (toolDesc.getMappings().contains(diagramElement.getMapping())) {
+ return toolDesc;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/VerticalSpaceExpansion.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/VerticalSpaceExpansion.java
new file mode 100644
index 0000000000..bc1ac9445e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/operation/VerticalSpaceExpansion.java
@@ -0,0 +1,339 @@
+/*******************************************************************************
+ * 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.business.internal.operation;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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.Size;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+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.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.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.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * An operation to shift all the atomic events on a sequence diagram below a
+ * certain point to make room.
+ *
+ * @author pcdavid, smonnier
+ */
+public class VerticalSpaceExpansion extends AbstractModelChangeOperation<Void> {
+
+ private final SequenceDiagram sequenceDiagram;
+
+ private int insertionPoint;
+
+ private int expansionSize;
+
+ private Set<ISequenceEvent> eventsToIgnore;
+
+ private Set<ISequenceNode> eventsToResize;
+
+ private Set<ISequenceNode> eventsToShift;
+
+ private Set<Message> messagesToResize;
+
+ private Set<Message> messagesToShift;
+
+ private Map<Message, Range> finalMessagesRanges;
+
+ private Integer move;
+
+ /**
+ * Constructor.
+ *
+ * @param diagram
+ * the sequence diagram in which to make the change.
+ * @param shift
+ * the zone to expand.
+ * @param move
+ * how much the main execution which triggered this change is
+ * vertically moved.
+ * @param eventsToIgnore
+ * the events which should be ignored, as they will be moved into
+ * the new space.
+ */
+ public VerticalSpaceExpansion(SequenceDiagram diagram, Range shift, Integer move, Collection<ISequenceEvent> eventsToIgnore) {
+ super("Auto-expand of " + shift);
+ this.sequenceDiagram = diagram;
+ this.move = move;
+ this.insertionPoint = shift.getLowerBound();
+ this.expansionSize = shift.width();
+ // Complete the specified eventsToIgnore with all their descendants.
+ this.eventsToIgnore = Sets.newHashSet();
+ for (ISequenceEvent evt : eventsToIgnore) {
+ this.eventsToIgnore.add(evt);
+ this.eventsToIgnore.addAll(new ISequenceEventQuery(evt).getAllDescendants());
+ this.eventsToIgnore.addAll(new ISequenceEventQuery(evt).getAllMessages());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute() {
+ categorizeSequenceNodes(findAllSequenceNodesToConsider());
+ categorizeMessages(findAllMessagesToConsider());
+ computeFinalMessageRanges();
+
+ expandLifelines();
+ shiftSequenceNodes();
+ resizeSequenceNodes();
+ setFinalMessagesRanges();
+
+ return null;
+ }
+
+ private void setFinalMessagesRanges() {
+ for (Message smep : finalMessagesRanges.keySet()) {
+ smep.setVerticalRange(finalMessagesRanges.get(smep));
+ // setMessageRange(smep, finalMessagesRanges.get(smep));
+ }
+ }
+
+ private void computeFinalMessageRanges() {
+ finalMessagesRanges = Maps.newHashMap();
+ Set<Message> messages = sequenceDiagram.getAllMessages();
+ for (Message msg : messages) {
+ if (messagesToShift.contains(msg)) {
+ if (!isConnectedToAMovedExecutionByASingleEnd(msg) && !isContainedReflexiveMessage(msg)) {
+ finalMessagesRanges.put(msg, msg.getVerticalRange().shifted(expansionSize));
+ } else {
+ finalMessagesRanges.put(msg, msg.getVerticalRange().shifted(move));
+ }
+ } else if (messagesToResize.contains(msg)) {
+ final Range rangeBefore = msg.getVerticalRange();
+ finalMessagesRanges.put(msg, new Range(rangeBefore.getLowerBound(), rangeBefore.getUpperBound() + expansionSize));
+ } else {
+ finalMessagesRanges.put(msg, msg.getVerticalRange());
+ }
+ }
+ }
+
+ private boolean isConnectedToAMovedExecutionByASingleEnd(Message msg) {
+ boolean onlySourceIsInMovedExecutions = eventsToIgnore.contains(msg.getSourceElement()) && !eventsToIgnore.contains(msg.getTargetElement());
+ boolean onlyTargetIsInMovedExecutions = !eventsToIgnore.contains(msg.getSourceElement()) && eventsToIgnore.contains(msg.getTargetElement());
+ return onlySourceIsInMovedExecutions || onlyTargetIsInMovedExecutions;
+ }
+
+ /**
+ * Expand all the lifelines which do not have a destroy message, but keep
+ * the messages they contain stable.
+ */
+ private void expandLifelines() {
+ List<Lifeline> lifelines = sequenceDiagram.getAllLifelines();
+ lifelines.removeAll(eventsToIgnore);
+ for (Lifeline lifeline : lifelines) {
+ Option<Message> cm = lifeline.getCreationMessage();
+ if (cm.some() && isStrictlyBelowInsertionPoint(cm.get())) {
+ /*
+ * The whole lifeline is below the insertion point.
+ */
+ InstanceRole irep = lifeline.getInstanceRole();
+ Node node = (Node) irep.getNotationView();
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Location) {
+ Location location = (Location) layoutConstraint;
+ location.setY(location.getY() + expansionSize);
+ }
+ } else {
+ /*
+ * Only the end of the lifeline is below the insertion point.
+ */
+ Option<Message> dm = lifeline.getDestructionMessage();
+ if (!dm.some() || isStrictlyBelowInsertionPoint(dm.get())) {
+ expandDown(lifeline, expansionSize);
+ }
+ }
+ }
+ }
+
+ /**
+ * Find all the executions in the diagram which may be affected by the
+ * operation. This is <em>all</em> the executions except the ones we are
+ * explicitly told to ignore (and their descendants).
+ */
+ private Set<ISequenceNode> findAllSequenceNodesToConsider() {
+ Set<ISequenceNode> sequenceNodes = Sets.newLinkedHashSet();
+ sequenceNodes.addAll(sequenceDiagram.getAllAbstractNodeEvents());
+ sequenceNodes.addAll(sequenceDiagram.getAllInteractionUses());
+ sequenceNodes.addAll(sequenceDiagram.getAllCombinedFragments());
+ sequenceNodes.addAll(sequenceDiagram.getAllOperands());
+ sequenceNodes.removeAll(eventsToIgnore);
+ return sequenceNodes;
+ }
+
+ private Set<Message> findAllMessagesToConsider() {
+ Set<Message> messages = Sets.newHashSet();
+ for (Message msg : sequenceDiagram.getAllMessages()) {
+ if (!isBetweenTwoMovedEvents(msg) || isContainedReflexiveMessage(msg)) {
+ messages.add(msg);
+ }
+ }
+ return messages;
+ }
+
+ private boolean isBetweenTwoMovedEvents(Message msg) {
+ return eventsToIgnore.contains(msg.getSourceElement()) && eventsToIgnore.contains(msg.getTargetElement());
+ }
+
+ /**
+ * Validate if the message is a reflexive message between two ignored
+ * executions
+ *
+ * @param msg
+ * a Message
+ * @return if the message "msg" is a reflexive message between two ignored
+ * executions
+ */
+ private boolean isContainedReflexiveMessage(Message msg) {
+ return eventsToIgnore.contains(msg.getSourceElement()) && eventsToIgnore.contains(msg.getTargetElement()) && msg.isReflective();
+ }
+
+ private void categorizeMessages(Set<Message> messages) {
+ messagesToResize = Sets.newHashSet();
+ messagesToShift = Sets.newHashSet();
+ for (Message ise : Iterables.filter(messages, Predicates.not(Predicates.in(eventsToIgnore)))) {
+ if (containsInsertionPoint(ise)) {
+ messagesToResize.add(ise);
+ } else if (isStrictlyBelowInsertionPoint(ise) || isConnectedToAMovedExecutionByASingleEnd(ise)) {
+ messagesToShift.add(ise);
+ }
+ }
+ }
+
+ /**
+ * Decide what needs to be done for each of the specified ISequenceNode:
+ * <ul>
+ * <li>nothing if it is above the expansion zone.</li>
+ * <li>a resize if it intersects the insertion point, i.e. its top is above
+ * the point but its bottom is below.</li>
+ * <li>a complete shift if it is completely below the insertion point.</li>
+ * </ul>
+ * <p>
+ * After completion of this method, <code>toResize</code> contains all the
+ * executions which need to be resized and <code>toShift</code> all the
+ * executions which need to be shifted.
+ */
+ private void categorizeSequenceNodes(Set<? extends ISequenceNode> sequenceNodes) {
+ eventsToResize = Sets.newHashSet();
+ eventsToShift = Sets.newHashSet();
+ for (ISequenceNode isn : sequenceNodes) {
+ if (isn instanceof ISequenceEvent) {
+ ISequenceEvent ise = (ISequenceEvent) isn;
+ if (containsInsertionPoint(ise)) {
+ eventsToResize.add(isn);
+ } else if (isStrictlyBelowInsertionPoint(ise) && !(isn instanceof Operand && eventsToShift.contains(((Operand) isn).getCombinedFragment()))) {
+ eventsToShift.add(isn);
+ }
+ }
+ }
+ }
+
+ private void shiftSequenceNodes() {
+
+ for (ISequenceNode nodes : Iterables.filter(eventsToShift, Predicates.not(Predicates.instanceOf(AbstractNodeEvent.class)))) {
+ shift(nodes, expansionSize);
+ }
+
+ for (AbstractNodeEvent execution : Iterables.filter(eventsToShift, AbstractNodeEvent.class)) {
+ Lifeline lep = execution.getLifeline().get();
+ Option<Message> cm = lep.getCreationMessage();
+ if (cm.some() && isStrictlyBelowInsertionPoint(cm.get())) {
+ continue;
+ }
+ /*
+ * Only actually shift the "top-level" executions. The rest will be
+ * moved along with their shifted ancestor, as execution position is
+ * relative to its parent.
+ */
+
+ if (!containsAncestors(eventsToShift, execution)) {
+ shift(execution, expansionSize);
+ }
+ }
+
+ for (AbstractNodeEvent execution : Iterables.filter(eventsToIgnore, AbstractNodeEvent.class)) {
+ /*
+ * Unshift events to ignore...
+ */
+ if (eventsToShift.contains(execution.getHierarchicalParentEvent())) {
+ shift(execution, -expansionSize);
+ }
+ }
+ }
+
+ private void resizeSequenceNodes() {
+ for (ISequenceNode ise : eventsToResize) {
+ expandDown(ise, expansionSize);
+ }
+ }
+
+ private boolean containsAncestors(Set<ISequenceNode> events, AbstractNodeEvent ise) {
+ ISequenceEvent parent = ise.getHierarchicalParentEvent();
+ if (parent == null || !(parent instanceof AbstractNodeEvent)) {
+ return false;
+ } else {
+ return Iterables.contains(events, parent) || containsAncestors(events, (AbstractNodeEvent) parent);
+ }
+ }
+
+ private boolean containsInsertionPoint(ISequenceEvent event) {
+ return event != null && event.getVerticalRange().includes(insertionPoint);
+ }
+
+ private boolean isStrictlyBelowInsertionPoint(ISequenceEvent event) {
+ return event != null && event.getVerticalRange().getLowerBound() > insertionPoint;
+ }
+
+ private void expandDown(Lifeline lifeline, int height) {
+ Range range = lifeline.getVerticalRange();
+ lifeline.setVerticalRange(new Range(range.getLowerBound(), range.getUpperBound() + height));
+ }
+
+ private void expandDown(ISequenceNode isn, int height) {
+ Node node = isn.getNotationNode();
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Size) {
+ Size s = (Size) layoutConstraint;
+ s.setHeight(s.getHeight() + height);
+ }
+ }
+
+ private void shift(ISequenceNode isn, int height) {
+ Node node = (Node) isn.getNotationView();
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Location && height != 0) {
+ Location location = (Location) layoutConstraint;
+ location.setY(location.getY() + height);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/EventEndHelper.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/EventEndHelper.java
new file mode 100644
index 0000000000..96deceb66b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/EventEndHelper.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.business.internal.ordering;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Function;
+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.diagram.sequence.SequenceDDiagram;
+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.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+
+/**
+ * Helper class to factor common code for semantic and graphical orders
+ * refreshing.
+ *
+ * @author mporhel
+ */
+public final class EventEndHelper {
+
+ /**
+ * Function to find and returns the EventEnds corresponding to the given
+ * part.
+ */
+ public static final Function<ISequenceEvent, List<EventEnd>> EVENT_ENDS = new Function<ISequenceEvent, List<EventEnd>>() {
+ public List<EventEnd> apply(ISequenceEvent from) {
+ return EventEndHelper.findEndsFromSemanticOrdering(from);
+ }
+ };
+
+ /**
+ * A function which compute the semantic end element from a event end.
+ */
+ public static final Function<EventEnd, EObject> SEMANTIC_END = new Function<EventEnd, EObject>() {
+ public EObject apply(EventEnd from) {
+ return from.getSemanticEnd();
+ }
+ };
+
+ /**
+ * A predicate which check that the given {@link SingleEventEnd} is a
+ * starting event.
+ */
+ public static final Predicate<SingleEventEnd> IS_START = new Predicate<SingleEventEnd>() {
+ public boolean apply(SingleEventEnd from) {
+ return from.isStart();
+ }
+ };
+
+ /**
+ * A predicate which check that the given {@link EventEnd} is a punctual
+ * compound event end.
+ */
+ public static final Predicate<EventEnd> PUNCTUAL_COMPOUND_EVENT_END = new Predicate<EventEnd>() {
+ public boolean apply(EventEnd input) {
+ return input instanceof CompoundEventEnd && EventEndHelper.getSemanticEvents(input).size() == 1;
+ }
+ };
+
+ private EventEndHelper() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Helper to get semanticEvents from an event end.
+ *
+ * @param eventEnd
+ * an EventEnd representing the end of an event.
+ * @return a list of semantic element representing the event itself.
+ */
+ public static List<EObject> getSemanticEvents(EventEnd eventEnd) {
+ List<EObject> result = Lists.newArrayList();
+ if (eventEnd instanceof SingleEventEnd) {
+ result.add(((SingleEventEnd) eventEnd).getSemanticEvent());
+ } else if (eventEnd instanceof CompoundEventEnd) {
+ result.addAll(((CompoundEventEnd) eventEnd).getSemanticEvents());
+ }
+ return result;
+ }
+
+ /**
+ * Helper to get the correct SingleEventEnd from an event end.
+ *
+ * @param eventEnd
+ * an EventEnd representing the end of an event.
+ * @param semanticEvent
+ * the wanted semantic event.
+ * @return a list of semantic element representing the event itself.
+ */
+ public static SingleEventEnd getSingleEventEnd(EventEnd eventEnd, EObject semanticEvent) {
+ SingleEventEnd result = null;
+ if (eventEnd instanceof SingleEventEnd) {
+ SingleEventEnd see = (SingleEventEnd) eventEnd;
+ if (semanticEvent != null && semanticEvent.equals(see.getSemanticEvent())) {
+ result = see;
+ }
+ } else if (eventEnd instanceof CompoundEventEnd) {
+ CompoundEventEnd cee = (CompoundEventEnd) eventEnd;
+ for (SingleEventEnd see : cee.getEventEnds()) {
+ if (semanticEvent != null && semanticEvent.equals(see.getSemanticEvent())) {
+ result = see;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Finds and returns the EventEnds corresponding to the given part, using
+ * the semantic ordering instead of the graphical ordering used by the plain
+ * {@link #findEnds(ISequenceEventEditPart)}.
+ *
+ * @param part
+ * the part to look for
+ * @return the EventEnds corresponding to the given part
+ */
+ public static List<EventEnd> findEndsFromSemanticOrdering(ISequenceEvent part) {
+ List<EventEnd> ends = Lists.newArrayList();
+ SequenceDiagram sdep = part.getDiagram();
+ SequenceDDiagram seqDiag = (SequenceDDiagram) sdep.getNotationDiagram().getElement();
+ Option<EObject> semanticEvent = part.getSemanticTargetElement();
+ for (EventEnd ee : seqDiag.getSemanticOrdering().getEventEnds()) {
+ if (semanticEvent.some() && EventEndHelper.getSemanticEvents(ee).contains(semanticEvent.get())) {
+ ends.add(ee);
+ }
+ }
+ return ends;
+ }
+
+ /**
+ * Filter the given list : remove the events linked by compound events.
+ *
+ * @param self
+ * the parent event part.
+ * @param childrenEvents
+ * event to filter.
+ * @return a filtered Iterable.
+ *
+ */
+ public static Iterable<ISequenceEvent> getIndependantEvents(ISequenceEvent self, Collection<ISequenceEvent> childrenEvents) {
+ final List<EventEnd> parentEnds = EventEndHelper.findEndsFromSemanticOrdering(self);
+ Predicate<ISequenceEvent> isValidSubEvent = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ List<EventEnd> inputEnds = EventEndHelper.findEndsFromSemanticOrdering(input);
+ boolean res = inputEnds.removeAll(parentEnds);
+ return !res;
+ }
+ };
+ return Iterables.filter(childrenEvents, isValidSubEvent);
+ }
+
+ /**
+ * Returns the list of direct compound-events of this given event, in
+ * chronological (and thus also graphical) order. This includes events with
+ * same semantic ends
+ *
+ * @param self
+ * The given {@link ISequenceEventEditPart}.
+ *
+ * @return the list of direct compound-events of this event, in
+ * chronological order.
+ */
+ public static List<ISequenceEvent> getCompoundEvents(ISequenceEvent self) {
+ List<ISequenceEvent> compoundEvents = Lists.newArrayList();
+ SequenceDiagram sdep = self.getDiagram();
+ EObject semanticEvent = self.getSemanticTargetElement().get();
+ List<EventEnd> ends = EventEndHelper.findEndsFromSemanticOrdering(self);
+ for (CompoundEventEnd cee : Iterables.filter(ends, CompoundEventEnd.class)) {
+ for (SingleEventEnd see : cee.getEventEnds()) {
+ if (see.getSemanticEvent() != semanticEvent) {
+ ISequenceEvent ise = EventEndHelper.findISequenceEvent(see, sdep);
+ // if (!isMessageToSelf(ise)) {
+ if (ise != null) {
+ compoundEvents.add(ise);
+ }
+ }
+ }
+ }
+ return compoundEvents;
+ }
+
+ /**
+ * 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 ISequenceEvent findISequenceEvent(SingleEventEnd end, SequenceDiagram sdep) {
+ for (ISequenceEvent ise : sdep.getAllDelimitedSequenceEvents()) {
+ Option<EObject> semanticEvent = ise.getSemanticTargetElement();
+ if (semanticEvent.some() && end.getSemanticEvent().equals(semanticEvent.get())) {
+ return ise;
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/RefreshOrderingHelper.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/RefreshOrderingHelper.java
new file mode 100644
index 0000000000..567916100d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/ordering/RefreshOrderingHelper.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * 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.business.internal.ordering;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ArrayListMultimap;
+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.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.AllContents;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerInterpreter;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager;
+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.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+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.State;
+import org.eclipse.sirius.diagram.sequence.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.sequence.ordering.CompoundEventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.OrderingFactory;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
+
+/**
+ * Helper class to factor common code for semantic and graphical orders
+ * refreshing.
+ *
+ * @author pcdavid
+ */
+public final class RefreshOrderingHelper {
+ @SuppressWarnings("unchecked")
+ private static final Predicate<DDiagramElement> DELIMITED_EVENT_PREDICATE = Predicates.or(AbstractNodeEvent.viewpointElementPredicate(), State.viewpointElementPredicate(), InteractionUse.viewpointElementPredicate(), CombinedFragment.viewpointElementPredicate(), Operand.viewpointElementPredicate());
+
+ private RefreshOrderingHelper() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Replaces the content of a list with new contents, but only if there are
+ * actual differences between the two versions.
+ *
+ * @param <T>
+ * the type of elements in the lists.
+ * @param oldValue
+ * the old list of values. Modified in place if necessary.
+ * @param newValue
+ * the new list of values. Not modified.
+ */
+ public static <T> void updateIfNeeded(List<T> oldValue, List<T> newValue) {
+ if (RefreshOrderingHelper.differentContents(oldValue, newValue)) {
+ oldValue.clear();
+ oldValue.addAll(newValue);
+ }
+ }
+
+ /**
+ * Determines if two lists have the same contents in the same order or not.
+ * Elements are compared using {@link #equals(Object)}.
+ *
+ * @param <T>
+ * the type of elements in the lists.
+ * @param oldValue
+ * the old list of values.
+ * @param newValue
+ * the new lists of values.
+ * @return <code>true</code> if the list of new values have different
+ * contents or the same elements but in a different order rom the
+ * old one.
+ */
+ public static <T> boolean differentContents(List<T> oldValue, List<T> newValue) {
+ if (oldValue.size() != newValue.size()) {
+ return true;
+ } else {
+ return !Iterables.elementsEqual(oldValue, newValue);
+ }
+ }
+
+ /**
+ * Returns all the starting and finishing ends of all the events in the
+ * specified diagram.
+ *
+ * @param sequenceDiagram
+ * a sequence diagram.
+ * @return all the starting and finishing ends of all the events in the
+ * specified diagram.
+ */
+ public static Iterable<? extends EventEnd> getAllEventEnds(SequenceDDiagram sequenceDiagram) {
+ Multimap<EObject, SingleEventEnd> semanticEndToSingleEventEnds = ArrayListMultimap.<EObject, SingleEventEnd> create();
+ List<EventEnd> result = Lists.newArrayList();
+
+ RefreshOrderingHelper.addAllSingleEventEnds(sequenceDiagram, semanticEndToSingleEventEnds);
+
+ RefreshOrderingHelper.minimizeEventEnds(result, semanticEndToSingleEventEnds);
+
+ return result;
+ }
+
+ private static void minimizeEventEnds(List<EventEnd> result, Multimap<EObject, SingleEventEnd> semanticEndToSingleEventEnds) {
+ for (EObject semanticEnd : semanticEndToSingleEventEnds.keySet()) {
+ Collection<SingleEventEnd> sees = semanticEndToSingleEventEnds.get(semanticEnd);
+ if (sees.isEmpty()) {
+ continue;
+ }
+
+ if (sees.size() == 1) {
+ result.add(sees.iterator().next());
+ } else {
+ CompoundEventEnd cee = OrderingFactory.eINSTANCE.createCompoundEventEnd();
+ cee.setSemanticEnd(semanticEnd);
+
+ if (sees.size() == 2 && RefreshOrderingHelper.countEvents(sees) == 1) {
+ // start first
+ Iterables.addAll(cee.getEventEnds(), Iterables.filter(sees, EventEndHelper.IS_START));
+ Iterables.addAll(cee.getEventEnds(), Iterables.filter(sees, Predicates.not(EventEndHelper.IS_START)));
+ } else {
+ // end first
+ Iterables.addAll(cee.getEventEnds(), Iterables.filter(sees, Predicates.not(EventEndHelper.IS_START)));
+ Iterables.addAll(cee.getEventEnds(), Iterables.filter(sees, EventEndHelper.IS_START));
+ }
+ result.add(cee);
+ }
+ }
+ }
+
+ private static int countEvents(Collection<SingleEventEnd> sees) {
+ Set<EObject> events = Sets.newHashSet();
+ for (SingleEventEnd see : sees) {
+ events.add(see.getSemanticEvent());
+ }
+ return events.size();
+ }
+
+ private static void addAllSingleEventEnds(SequenceDDiagram sequenceDiagram, Multimap<EObject, SingleEventEnd> semanticEndToSingleEventEnd) {
+
+ // Messages
+ for (DEdge edge : Iterables.filter(sequenceDiagram.getEdges(), Message.viewpointElementPredicate())) {
+ /*
+ * Target may be null if the semantic element has been removed from
+ * the model but the canonical refresh has not happened yet.
+ */
+ if (edge.getTarget() != null) {
+ RefreshOrderingHelper.add(RefreshOrderingHelper.getStartingEnd(edge, DescriptionPackage.eINSTANCE.getMessageMapping_SendingEndFinderExpression()), semanticEndToSingleEventEnd);
+ RefreshOrderingHelper.add(RefreshOrderingHelper.getFinishingEnd(edge, DescriptionPackage.eINSTANCE.getMessageMapping_ReceivingEndFinderExpression()), semanticEndToSingleEventEnd);
+ }
+ }
+
+ // Delimited elements : Executions, States, InteractionUse, Frames,
+ // Operands
+ for (DDiagramElement node : Iterables.filter(Iterables.filter(AllContents.of(sequenceDiagram), DDiagramElement.class), RefreshOrderingHelper.DELIMITED_EVENT_PREDICATE)) {
+ /*
+ * Target may be null if the semantic element has been removed from
+ * the model but the canonical refresh has not happened yet.
+ */
+ if (node.getTarget() != null) {
+ SingleEventEnd startingEnd = RefreshOrderingHelper.getStartingEnd(node, DescriptionPackage.eINSTANCE.getDelimitedEventMapping_StartingEndFinderExpression());
+ SingleEventEnd finishingEnd = RefreshOrderingHelper.getFinishingEnd(node, DescriptionPackage.eINSTANCE.getDelimitedEventMapping_FinishingEndFinderExpression());
+
+ RefreshOrderingHelper.add(startingEnd, semanticEndToSingleEventEnd);
+ RefreshOrderingHelper.add(finishingEnd, semanticEndToSingleEventEnd);
+ }
+ }
+ }
+
+ private static void add(SingleEventEnd see, Multimap<EObject, SingleEventEnd> endToEventEnds) {
+ if (see != null && see.getSemanticEnd() != null) {
+ endToEventEnds.put(see.getSemanticEnd(), see);
+ }
+ }
+
+ /**
+ * Helper to create an event end representing the start of an event.
+ *
+ * @param semanticEvent
+ * the semantic element representing the event itself.
+ * @param semanticEnd
+ * the semantic element representing the starting end of the
+ * event.
+ * @return an EventEnd representing the starting end of the event.
+ */
+ public static SingleEventEnd createStartingEventEnd(EObject semanticEvent, EObject semanticEnd) {
+ SingleEventEnd result = OrderingFactory.eINSTANCE.createSingleEventEnd();
+ result.setStart(true);
+ result.setSemanticEvent(semanticEvent);
+ result.setSemanticEnd(semanticEnd);
+ return result;
+ }
+
+ /**
+ * Helper to create an event end representing the finishing of an event.
+ *
+ * @param semanticEvent
+ * the semantic element representing the event itself.
+ * @param semanticEnd
+ * the semantic element representing the finishing end of the
+ * event.
+ * @return an EventEnd representing the finishing end of the event.
+ */
+ public static SingleEventEnd createFinishingEventEnd(EObject semanticEvent, EObject semanticEnd) {
+ SingleEventEnd result = OrderingFactory.eINSTANCE.createSingleEventEnd();
+ result.setStart(false);
+ result.setSemanticEvent(semanticEvent);
+ result.setSemanticEnd(semanticEnd);
+ return result;
+ }
+
+ private static SingleEventEnd getStartingEnd(DDiagramElement dde, EAttribute startingEnd) {
+ EObject semanticEvent = dde.getTarget();
+ IInterpreter interpreter = InterpreterUtil.getInterpreter(dde);
+ RuntimeLoggerInterpreter loggerInterpreter = RuntimeLoggerManager.INSTANCE.decorate(interpreter);
+ EObject sendingEnd = loggerInterpreter.evaluateEObject(semanticEvent, dde.getDiagramElementMapping(), startingEnd);
+ return RefreshOrderingHelper.createStartingEventEnd(semanticEvent, sendingEnd);
+ }
+
+ private static SingleEventEnd getFinishingEnd(DDiagramElement dde, EAttribute finishingEnd) {
+ EObject semanticEvent = dde.getTarget();
+ IInterpreter interpreter = InterpreterUtil.getInterpreter(dde);
+ RuntimeLoggerInterpreter loggerInterpreter = RuntimeLoggerManager.INSTANCE.decorate(interpreter);
+ EObject receivingEnd = loggerInterpreter.evaluateEObject(semanticEvent, dde.getDiagramElementMapping(), finishingEnd);
+ return RefreshOrderingHelper.createFinishingEventEnd(semanticEvent, receivingEnd);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceElementQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceElementQuery.java
new file mode 100644
index 0000000000..2a435466ad
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceElementQuery.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.AbsoluteBoundsFilter;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceElement;
+
+/**
+ * General queries on {@link ISequenceElement}s.
+ *
+ * @author pcdavid
+ */
+public class ISequenceElementQuery {
+ /**
+ * The event to query.
+ */
+ protected final ISequenceElement event;
+
+ /**
+ * Constructor.
+ *
+ * @param event
+ * the event to query.
+ */
+ public ISequenceElementQuery(ISequenceElement event) {
+ this.event = Preconditions.checkNotNull(event);
+ }
+
+ /**
+ * Check the presence of the absolute bounds flag.
+ *
+ * @return true if the element is flagged.
+ */
+ public boolean hasAbsoluteBoundsFlag() {
+ if (event.getNotationView() != null && event.getNotationView().getElement() instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) event.getNotationView().getElement();
+ return !Iterables.isEmpty(Iterables.filter(dde.getGraphicalFilters(), AbsoluteBoundsFilter.class));
+ }
+ return false;
+ }
+
+ /**
+ * Return the flagged absolute bounds, ie the last known logical bounds.
+ *
+ * @return the flagged absolute bounds.
+ */
+ public Rectangle getFlaggedAbsoluteBounds() {
+ Rectangle bounds = new Rectangle();
+ if (event.getNotationView() != null && event.getNotationView().getElement() instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) event.getNotationView().getElement();
+ Iterable<AbsoluteBoundsFilter> flags = Iterables.filter(dde.getGraphicalFilters(), AbsoluteBoundsFilter.class);
+ if (!Iterables.isEmpty(flags)) {
+ AbsoluteBoundsFilter flag = flags.iterator().next();
+ bounds.x = safeGetInt(flag.getX());
+ bounds.y = safeGetInt(flag.getY());
+ bounds.width = safeGetInt(flag.getWidth());
+ bounds.height = safeGetInt(flag.getHeight());
+ }
+ }
+ return bounds;
+ }
+
+ private int safeGetInt(Integer i) {
+ return i == null ? 0 : i;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceEventQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceEventQuery.java
new file mode 100644
index 0000000000..67b7d6a6a3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ISequenceEventQuery.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+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.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.Message;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * General queries on {@link ISequenceEvent}s.
+ *
+ * @author pcdavid
+ */
+public class ISequenceEventQuery {
+ /**
+ * The event to query.
+ */
+ protected final ISequenceEvent event;
+
+ /**
+ * Constructor.
+ *
+ * @param event
+ * the event to query.
+ */
+ public ISequenceEventQuery(ISequenceEvent event) {
+ this.event = Preconditions.checkNotNull(event);
+ }
+
+ /**
+ * Tests whether this event is an ancestor of the specified child event.
+ *
+ * @param child
+ * the potential descendant.
+ * @return <code>true</code> if <em>this</em> event is identical to the
+ * child, the parent of the child or an indirect ancestor of the
+ * child.
+ */
+ public boolean isAncestorOrSelf(ISequenceEvent child) {
+ ISequenceEvent iSequenceEvent = event;
+ final boolean result;
+ if (iSequenceEvent == null || child == null) {
+ result = false;
+ } else if (iSequenceEvent.equals(child)) {
+ result = true;
+ } else {
+ ISequenceEvent parentEvent = child.getParentEvent();
+ if (iSequenceEvent.equals(parentEvent)) {
+ result = true;
+ } else {
+ result = parentEvent != null && isAncestorOrSelf(parentEvent);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Tests whether this event is a reflective message.
+ *
+ * @return <code>true</code> if this event is a reflective message.
+ */
+ public boolean isReflectiveMessage() {
+ return event instanceof Message && ((Message) event).isReflective();
+ }
+
+ /**
+ * Computes all the descendants of the specified execution, i.e. the
+ * recursive transitive closure on getSubEvents().
+ *
+ * The current ise is not included.
+ *
+ * @return all the proper descendant events of the given sequence event.
+ */
+ public Set<ISequenceEvent> getAllDescendants() {
+ return getAllDescendants(false, ISequenceEvent.ISEQUENCEEVENT_NOTATION_PREDICATE);
+ }
+
+ /**
+ * Computes all the descendants of the specified execution, i.e. the
+ * recursive transitive closure on getSubEvents().
+ *
+ * @param includeSelf
+ * whether or not to consider "self" as a descendant.
+ * @return all the proper descendant events of the given sequence event.
+ */
+ public Set<ISequenceEvent> getAllDescendants(boolean includeSelf) {
+ return getAllDescendants(includeSelf, ISequenceEvent.ISEQUENCEEVENT_NOTATION_PREDICATE);
+ }
+
+ /**
+ * Computes all the descendants of the specified execution, i.e. the
+ * recursive transitive closure on getSubEvents().
+ *
+ * @param includeSelf
+ * whether or not to consider "self" as a descendant.
+ * @param predicate
+ * the predicate to select which descendants to include in the
+ * collection.
+ * @return all the proper descendant events of the given execution.
+ */
+ public Set<ISequenceEvent> getAllDescendants(boolean includeSelf, Predicate<? super View> predicate) {
+ Set<ISequenceEvent> result = Sets.newHashSet();
+ addAllDescendants(predicate, result);
+ if (!includeSelf) {
+ result.remove(event);
+ }
+ return result;
+ }
+
+ /**
+ * Adds all the descendants of the specified edit part which verify the
+ * predicate into a collection. Only children edit parts are considered, not
+ * source and target connections.
+ *
+ * @param predicate
+ * the predicate to select which descendants to include in the
+ * collection.
+ * @param parts
+ * the collection in which to add all the descendants of
+ * <code>element</code> which verify the predicate.
+ */
+ private void addAllDescendants(Predicate<? super View> predicate, Collection<ISequenceEvent> parts) {
+ addAllDescendants(event, predicate, parts);
+ }
+
+ private void addAllDescendants(ISequenceEvent ise, Predicate<? super View> predicate, Collection<ISequenceEvent> parts) {
+ View element = ise.getNotationView();
+ if (predicate.apply(element)) {
+ Option<ISequenceEvent> iSequenceEvent = ISequenceElementAccessor.getISequenceEvent(element);
+ if (iSequenceEvent.some()) {
+ parts.add(iSequenceEvent.get());
+ }
+ }
+ for (ISequenceEvent childEvent : ise.getSubEvents()) {
+ addAllDescendants(childEvent, predicate, parts);
+ }
+ }
+
+ /**
+ * Finds all the executions without duplicates.
+ *
+ * @return the found executions found.
+ */
+ public Collection<Execution> getAllExecutions() {
+ return Lists.newArrayList(Iterables.filter(getAllDescendants(true, Execution.notationPredicate()), Execution.class));
+ }
+
+ /**
+ * Finds all the sequence messages whose source or target is the specified
+ * element or any of its descendant edit parts, without duplicates.
+ *
+ * @return the messages found without duplicates.
+ */
+ public Set<Message> getAllMessages() {
+ Set<Message> allMessages = Sets.newHashSet();
+ allMessages.addAll(getAllMessagesFrom());
+ allMessages.addAll(getAllMessagesTo());
+ return allMessages;
+ }
+
+ /**
+ * Finds all the sequence messages whose source is the specified element or
+ * any of its descendant edit parts.
+ *
+ * @return the messages found.
+ */
+ public List<Message> getAllMessagesFrom() {
+ List<Message> messagesParts = Lists.newArrayList();
+ addAllMessagesFrom(event.getNotationView(), messagesParts);
+ return messagesParts;
+ }
+
+ /**
+ * Finds all the sequence messages whose target is the specified element or
+ * any of its descendant edit parts.
+ *
+ * @return the messages found.
+ */
+ public List<Message> getAllMessagesTo() {
+ List<Message> messagesParts = Lists.newArrayList();
+ addAllMessagesTo(event.getNotationView(), messagesParts);
+ return messagesParts;
+ }
+
+ /**
+ * 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 void addAllMessagesTo(View element, Collection<Message> messages) {
+ for (Edge connectionPart : Iterables.filter(Iterables.filter(element.getTargetEdges(), Edge.class), Message.notationPredicate())) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(connectionPart);
+ if (message.some()) {
+ messages.add(message.get());
+ }
+ }
+ if (element instanceof Message) {
+ messages.add((Message) element);
+ }
+ for (View child : Iterables.filter(element.getChildren(), Node.class)) {
+ addAllMessagesFrom(child, messages);
+ }
+ }
+
+ /**
+ * 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 void addAllMessagesFrom(View element, Collection<Message> messages) {
+ for (Edge connectionPart : Iterables.filter(Iterables.filter(element.getSourceEdges(), Edge.class), Message.notationPredicate())) {
+ Option<Message> message = ISequenceElementAccessor.getMessage(connectionPart);
+ if (message.some()) {
+ messages.add(message.get());
+ }
+ }
+ if (element instanceof Message) {
+ messages.add((Message) element);
+ }
+ for (View child : Iterables.filter(element.getChildren(), Node.class)) {
+ addAllMessagesFrom(child, messages);
+ }
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#getOccupiedRange()}.
+ *
+ * @return the maximal range occupied by children of the event.
+ */
+ public Range getOccupiedRange() {
+ Range range = Range.emptyRange();
+ for (ISequenceEvent child : event.getSubEvents()) {
+ range = range.union(child.getVerticalRange());
+ }
+ return range;
+ }
+
+ /**
+ * Return all moved elements from the context.
+ *
+ * @return the all moved elements.
+ */
+ public Set<ISequenceEvent> getAllSequenceEventToMoveWith() {
+ Set<ISequenceEvent> entryPoints = Sets.newHashSet();
+ return getAllSequenceEventToMoveWith(entryPoints);
+ }
+
+ /**
+ * Return all moved elements from the context.
+ *
+ * @param additionnalEntryPoints
+ * additionnal entry points.
+ * @return the all moved elements.
+ */
+ public Set<ISequenceEvent> getAllSequenceEventToMoveWith(Collection<ISequenceEvent> additionnalEntryPoints) {
+ Set<ISequenceEvent> entryPoints = Sets.newHashSet();
+ entryPoints.add(event);
+ entryPoints.addAll(additionnalEntryPoints);
+
+ Set<ISequenceEvent> moved = Sets.newHashSet();
+ for (ISequenceEvent ise : entryPoints) {
+ populateMovedElements(ise, moved);
+ }
+ return moved;
+ }
+
+ private void populateMovedElements(ISequenceEvent inspectedElement, Set<ISequenceEvent> moved) {
+ moved.add(inspectedElement);
+ for (ISequenceEvent subEvent : Iterables.filter(inspectedElement.getEventsToMoveWith(), Predicates.not(Predicates.in(moved)))) {
+ populateMovedElements(subEvent, moved);
+ }
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/InstanceRoleQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/InstanceRoleQuery.java
new file mode 100644
index 0000000000..18a339ed71
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/InstanceRoleQuery.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.RGBValues;
+import org.eclipse.sirius.business.api.diagramtype.HeaderData;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InstanceRole;
+
+/**
+ * General queries on {@link InstanceRole}s.
+ *
+ * @author lredor
+ */
+public class InstanceRoleQuery {
+ /**
+ * The Instance role to query.
+ */
+ protected final InstanceRole instanceRole;
+
+ /**
+ * Constructor.
+ *
+ * @param instanceRole
+ * the instance role to query.
+ */
+ public InstanceRoleQuery(InstanceRole instanceRole) {
+ this.instanceRole = Preconditions.checkNotNull(instanceRole);
+ }
+
+ /**
+ * Get the header data corresponding to this instance role.
+ *
+ * @return the header data corresponding to this instance role.
+ */
+ public HeaderData getHeaderData() {
+ Option<RGBValues> optionalBackgroundColor = instanceRole.getBackgroundColor();
+ Option<RGBValues> optionalLabelColor = instanceRole.getLabelColor();
+ return new HeaderData(instanceRole.getName(), instanceRole.getBounds().x, instanceRole.getBounds().width, optionalBackgroundColor.get(), optionalLabelColor.get());
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/RangeComparator.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/RangeComparator.java
new file mode 100644
index 0000000000..c1efc1fb03
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/RangeComparator.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.List;
+
+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.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * {@link Comparator} used to order Set of {@link ISequenceElement} according to
+ * their {@link Range#getLowerBound()}.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class RangeComparator implements Comparator<ISequenceElement>, Serializable {
+
+ /**
+ * Generated SUID.
+ */
+ private static final long serialVersionUID = -8968333614931292746L;
+
+ /**
+ * Overridden to compare {@link ISequenceElement} order according to their
+ * {@link Range}.
+ *
+ * {@inheritDoc}
+ */
+ public int compare(ISequenceElement sequenceElement1, ISequenceElement sequenceElement2) {
+ Range sequenceElement1Range = Range.verticalRange(sequenceElement1.getProperLogicalBounds());
+ Range sequenceElement2Range = Range.verticalRange(sequenceElement2.getProperLogicalBounds());
+ int comparison = sequenceElement1Range.getLowerBound() - sequenceElement2Range.getLowerBound();
+ if (comparison == 0) {
+ if (sequenceElement1 instanceof ISequenceEvent && sequenceElement2 instanceof ISequenceEvent) {
+ ISequenceEvent sequenceEvent1 = (ISequenceEvent) sequenceElement1;
+ ISequenceEvent sequenceEvent2 = (ISequenceEvent) sequenceElement2;
+
+ SequenceDiagram sequenceDiagram = sequenceElement1.getDiagram();
+
+ List<EventEnd> sequenceEvent1EventEnds = sequenceDiagram.findEnds(sequenceEvent1);
+ List<EventEnd> sequenceEvent2EventEnds = sequenceDiagram.findEnds(sequenceEvent2);
+
+ if (!sequenceEvent1EventEnds.isEmpty() && !sequenceEvent2EventEnds.isEmpty()) {
+ EventEnd firstEventEndOfSequenceEvent1 = sequenceEvent1EventEnds.get(0);
+ EventEnd firstEventEndOfSequenceEvent2 = sequenceEvent2EventEnds.get(0);
+ List<EventEnd> eventEnds = sequenceDiagram.getSequenceDDiagram().getGraphicalOrdering().getEventEnds();
+ comparison = eventEnds.indexOf(firstEventEndOfSequenceEvent1) - eventEnds.indexOf(firstEventEndOfSequenceEvent2);
+ }
+ }
+
+ }
+ return comparison;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ReversedRangeComparator.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ReversedRangeComparator.java
new file mode 100644
index 0000000000..6d8261af82
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/ReversedRangeComparator.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.List;
+
+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.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * {@link Comparator} used to order Set of {@link ISequenceElement} according to
+ * their {@link Range#getUpperBound()}.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class ReversedRangeComparator implements Comparator<ISequenceElement>, Serializable {
+
+ /**
+ * Generated SUID.
+ */
+ private static final long serialVersionUID = -962057468507177598L;
+
+ /**
+ * Overridden to compare {@link ISequenceElement} order according to their
+ * range from upper to lower.
+ *
+ * {@inheritDoc}
+ */
+ public int compare(ISequenceElement sequenceElement1, ISequenceElement sequenceElement2) {
+ Range sequenceElement1Range = Range.verticalRange(sequenceElement1.getProperLogicalBounds());
+ Range sequenceElement2Range = Range.verticalRange(sequenceElement2.getProperLogicalBounds());
+ int comparison = sequenceElement1Range.getUpperBound() - sequenceElement2Range.getUpperBound();
+ if (comparison == 0) {
+ if (sequenceElement1 instanceof ISequenceEvent && sequenceElement2 instanceof ISequenceEvent) {
+ ISequenceEvent sequenceEvent1 = (ISequenceEvent) sequenceElement1;
+ ISequenceEvent sequenceEvent2 = (ISequenceEvent) sequenceElement2;
+
+ SequenceDiagram sequenceDiagram = sequenceElement1.getDiagram();
+
+ List<EventEnd> sequenceEvent1EventEnds = sequenceDiagram.findEnds(sequenceEvent1);
+ List<EventEnd> sequenceEvent2EventEnds = sequenceDiagram.findEnds(sequenceEvent2);
+
+ if (!sequenceEvent1EventEnds.isEmpty() && !sequenceEvent2EventEnds.isEmpty()) {
+ EventEnd lastEventEndOfSequenceEvent1 = sequenceEvent1EventEnds.get(sequenceEvent1EventEnds.size() - 1);
+ EventEnd lastEventEndOfSequenceEvent2 = sequenceEvent2EventEnds.get(sequenceEvent2EventEnds.size() - 1);
+ List<EventEnd> eventEnds = sequenceDiagram.getSequenceDDiagram().getGraphicalOrdering().getEventEnds();
+ comparison = eventEnds.indexOf(lastEventEndOfSequenceEvent2) - eventEnds.indexOf(lastEventEndOfSequenceEvent1);
+ }
+ }
+
+ }
+ return comparison;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramDescriptionQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramDescriptionQuery.java
new file mode 100644
index 0000000000..55c43e9a92
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramDescriptionQuery.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.business.internal.query;
+
+import java.util.Iterator;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+
+import org.eclipse.sirius.diagram.sequence.description.EndOfLifeMapping;
+import org.eclipse.sirius.diagram.sequence.description.ExecutionMapping;
+import org.eclipse.sirius.diagram.sequence.description.InstanceRoleMapping;
+import org.eclipse.sirius.diagram.sequence.description.MessageMapping;
+import org.eclipse.sirius.diagram.sequence.description.SequenceDiagramDescription;
+
+/**
+ * Queries from a {@link SequenceDiagramDescription}.
+ *
+ * @author cbrun
+ *
+ */
+public class SequenceDiagramDescriptionQuery {
+
+ private SequenceDiagramDescription diag;
+
+ /**
+ * Create the queries.
+ *
+ * @param diag
+ * the source of the queries.
+ */
+ public SequenceDiagramDescriptionQuery(SequenceDiagramDescription diag) {
+ this.diag = diag;
+ }
+
+ /**
+ * return any InstanceRoleMapping contained in the diagram having the given
+ * name.
+ *
+ * @param name
+ * name of the searched element.
+ * @return any InstanceRoleMapping contained in the diagram having the given
+ * name.
+ */
+ public Iterator<InstanceRoleMapping> getInstanceRoleMappings(final String name) {
+ return Iterators.filter(Iterators.filter(diag.eAllContents(), InstanceRoleMapping.class), new Predicate<InstanceRoleMapping>() {
+
+ public boolean apply(InstanceRoleMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+
+ /**
+ * return any ExecutionMapping contained in the diagram having the given
+ * name.
+ *
+ * @param name
+ * name of the searched element.
+ * @return any ExecutionMapping contained in the diagram having the given
+ * name.
+ */
+ public Iterator<ExecutionMapping> getExecutionMappings(final String name) {
+ return Iterators.filter(Iterators.filter(diag.eAllContents(), ExecutionMapping.class), new Predicate<ExecutionMapping>() {
+
+ public boolean apply(ExecutionMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+
+ /**
+ * return any {@link EndOfLifeMapping} contained in the diagram having the
+ * given name.
+ *
+ * @param name
+ * name of the searched element.
+ * @return any EndOfLifeMapping contained in the diagram having the given
+ * name.
+ */
+ public Iterator<EndOfLifeMapping> getEndOfLifeMappings(final String name) {
+ return Iterators.filter(Iterators.filter(diag.eAllContents(), EndOfLifeMapping.class), new Predicate<EndOfLifeMapping>() {
+
+ public boolean apply(EndOfLifeMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+
+ /**
+ * return any {@link MessageMapping} contained in the diagram having the
+ * given name.
+ *
+ * @param name
+ * name of the searched element.
+ * @return any MessageMapping contained in the diagram having the given
+ * name.
+ */
+ public Iterator<MessageMapping> getMessageMappings(final String name) {
+ return Iterators.filter(Iterators.filter(diag.eAllContents(), MessageMapping.class), new Predicate<MessageMapping>() {
+
+ public boolean apply(MessageMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramQuery.java
new file mode 100644
index 0000000000..d3edccffe6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceDiagramQuery.java
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import com.google.common.base.Preconditions;
+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.AbstractFrame;
+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.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IBorderItemOffsets;
+
+/**
+ * Queries from a {@link SequenceDiagram}.
+ *
+ * @author edugueperoux
+ *
+ */
+public class SequenceDiagramQuery {
+
+ private static final String ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM = "contextual SequenceDiagram can't be null";
+
+ private static final String ASSERT_MESSAGE_ON_TIME_POINT = "timePoint must be strictly positive";
+
+ private SequenceDiagram sequenceDiagram;
+
+ /**
+ * Create the query.
+ *
+ * @param sequenceDiagram
+ * the source of the query.
+ */
+ public SequenceDiagramQuery(SequenceDiagram sequenceDiagram) {
+ this.sequenceDiagram = sequenceDiagram;
+ }
+
+ /**
+ * Get all {@link ISequenceEvent} of the current {@link SequenceDiagram}
+ * with range's lower bound strictly inferior to timePoint.
+ *
+ * @param timePoint
+ * the timePoint from which get all lower {@link ISequenceEvent}
+ *
+ * @return the set of {@link ISequenceEvent} lower timePoint, sorted by
+ * range from lower to upper
+ */
+ public Set<ISequenceEvent> getAllSequenceEventsLowerThan(int timePoint) {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ Preconditions.checkArgument(timePoint > 0, ASSERT_MESSAGE_ON_TIME_POINT);
+
+ Set<ISequenceEvent> sequenceEventLowers = new TreeSet<ISequenceEvent>(new RangeComparator());
+ for (ISequenceEvent sequenceEvent : getAllSequenceEvents()) {
+ Range sequenceEventRange = sequenceEvent.getVerticalRange();
+ if (sequenceEventRange.getLowerBound() < timePoint) {
+ sequenceEventLowers.add(sequenceEvent);
+ }
+ }
+ return sequenceEventLowers;
+ }
+
+ /**
+ * Get all {@link ISequenceEvent} of the current {@link SequenceDiagram}
+ * with range's including strictly timePoint.
+ *
+ * @param timePoint
+ * the timePoint from which get all {@link ISequenceEvent}
+ * including it in their range
+ *
+ * @return the set of {@link ISequenceEvent} having timePoint in their
+ * range, sorted by range from lower to upper
+ */
+ public Set<ISequenceEvent> getAllSequenceEventsOn(int timePoint) {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ Preconditions.checkArgument(timePoint > 0, ASSERT_MESSAGE_ON_TIME_POINT);
+
+ Set<ISequenceEvent> sequenceEventOns = new TreeSet<ISequenceEvent>(new RangeComparator());
+ for (ISequenceEvent sequenceEvent : getAllSequenceEvents()) {
+ Range sequenceEventRange = sequenceEvent.getVerticalRange();
+ if (sequenceEventRange.includes(timePoint)) {
+ sequenceEventOns.add(sequenceEvent);
+ }
+ }
+ return sequenceEventOns;
+ }
+
+ /**
+ * Get all {@link ISequenceEvent} of the current {@link SequenceDiagram}
+ * with range's lowerbound strictly upper to timePoint.
+ *
+ * @param timePoint
+ * the timePoint from which get all upper {@link ISequenceEvent}
+ *
+ * @return the set of {@link ISequenceEvent} upper timePoint, sorted by
+ * range from lower to upper
+ */
+ public Set<ISequenceEvent> getAllSequenceEventsUpperThan(int timePoint) {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ Preconditions.checkArgument(timePoint > 0, ASSERT_MESSAGE_ON_TIME_POINT);
+
+ Set<ISequenceEvent> sequenceEventUppers = new TreeSet<ISequenceEvent>(new RangeComparator());
+ for (ISequenceEvent sequenceEvent : getAllSequenceEvents()) {
+ Range sequenceEventRange = sequenceEvent.getVerticalRange();
+ if (sequenceEventRange.getLowerBound() > timePoint) {
+ sequenceEventUppers.add(sequenceEvent);
+ }
+ }
+ return sequenceEventUppers;
+ }
+
+ /**
+ * Get all {@link ISequenceEvent} of the current {@link SequenceDiagram}.
+ *
+ * @return the set of {@link ISequenceEvent} of the current
+ * {@link SequenceDiagram}, sorted by range from lower to upper
+ */
+ public Set<ISequenceEvent> getAllSequenceEvents() {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+
+ Set<ISequenceEvent> allSequenceEvents = new TreeSet<ISequenceEvent>(new RangeComparator());
+ allSequenceEvents.addAll(sequenceDiagram.getAllLifelines());
+ allSequenceEvents.addAll(sequenceDiagram.getAllAbstractNodeEvents());
+ allSequenceEvents.addAll(sequenceDiagram.getAllMessages());
+ allSequenceEvents.addAll(sequenceDiagram.getAllInteractionUses());
+ allSequenceEvents.addAll(sequenceDiagram.getAllCombinedFragments());
+ allSequenceEvents.addAll(sequenceDiagram.getAllOperands());
+ allSequenceEvents.addAll(sequenceDiagram.getAllStates());
+ return allSequenceEvents;
+ }
+
+ /**
+ * Get all {@link ISequenceEvent} of the current {@link SequenceDiagram} of
+ * the specified {@link Lifeline}.
+ *
+ * @param lifeline
+ * the specified {@link Lifeline}
+ *
+ * @return the set of {@link ISequenceEvent} of the current
+ * {@link SequenceDiagram} of the specified {@link Lifeline}, sorted
+ * by range from lower to upper
+ */
+ public Set<ISequenceEvent> getAllSequenceEventsOnLifeline(Lifeline lifeline) {
+ Set<ISequenceEvent> allSequenceEventsOnLifeline = new TreeSet<ISequenceEvent>(new RangeComparator());
+ for (ISequenceEvent sequenceEvent : Iterables.filter(getAllSequenceEvents(), Predicates.not(Predicates.instanceOf(Lifeline.class)))) {
+ Option<Lifeline> lifelineOfSequenceEventOption = sequenceEvent.getLifeline();
+ if (lifelineOfSequenceEventOption.some() && lifelineOfSequenceEventOption.get().equals(lifeline)) {
+ allSequenceEventsOnLifeline.add(sequenceEvent);
+ } else if (!lifelineOfSequenceEventOption.some()) {
+ if (sequenceEvent instanceof Message) {
+ Message message = (Message) sequenceEvent;
+ Option<Lifeline> sourceLifelineOption = message.getSourceLifeline();
+ Option<Lifeline> targetLifelineOption = message.getTargetLifeline();
+ if (sourceLifelineOption.some() && sourceLifelineOption.get().equals(lifeline)) {
+ allSequenceEventsOnLifeline.add(message);
+ } else if (targetLifelineOption.some() && targetLifelineOption.get().equals(lifeline)) {
+ allSequenceEventsOnLifeline.add(message);
+ }
+ } else if (sequenceEvent instanceof AbstractFrame) {
+ AbstractFrame abstractFrame = (AbstractFrame) sequenceEvent;
+ Collection<Lifeline> coveredLifelines = abstractFrame.computeCoveredLifelines();
+ if (coveredLifelines.contains(lifeline)) {
+ allSequenceEventsOnLifeline.add(abstractFrame);
+ }
+ }
+ }
+ }
+ return allSequenceEventsOnLifeline;
+ }
+
+ /**
+ * Get all events having at least one bound on the given {@link Lifeline} in
+ * the given range.
+ *
+ * @param lifeline
+ * the lifeline to check.
+ * @param inclusionRange
+ * the range to look in.
+ * @return events on the given lifeline and range.
+ */
+ public SortedSet<ISequenceEvent> getAllSequenceEventsOnLifelineOnRange(Lifeline lifeline, Range inclusionRange) {
+ SortedSet<ISequenceEvent> allSequenceEventsOnLifelineStrictlyIncludedBetween = new TreeSet<ISequenceEvent>(new RangeComparator());
+ for (ISequenceEvent sequenceEvent : getAllSequenceEventsOnLifeline(lifeline)) {
+ Range sequenceEventRange = sequenceEvent.getVerticalRange();
+ if (inclusionRange.includesAtLeastOneBound(sequenceEventRange)) {
+ allSequenceEventsOnLifelineStrictlyIncludedBetween.add(sequenceEvent);
+ }
+ }
+ return allSequenceEventsOnLifelineStrictlyIncludedBetween;
+ }
+
+ /**
+ * Get all {@link ISequenceNode} of the current {@link SequenceDiagram} with
+ * range's lowerbound strictly lower to timePoint.
+ *
+ * @param timePoint
+ * the timePoint from which get all lower {@link ISequenceNode}
+ *
+ * @return the set of {@link ISequenceNode} lower timePoint, sorted by range
+ * from lower to upper
+ */
+ public Set<ISequenceNode> getAllSequenceNodesLowerThan(int timePoint) {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ Preconditions.checkArgument(timePoint > 0, ASSERT_MESSAGE_ON_TIME_POINT);
+
+ Set<ISequenceNode> sequenceNodeLowers = new TreeSet<ISequenceNode>(new RangeComparator());
+ for (ISequenceNode sequenceNode : getAllSequenceNodes()) {
+ Range sequenceNodeRange = Range.verticalRange(sequenceNode.getBounds());
+ if (sequenceNodeRange.getLowerBound() < timePoint) {
+ sequenceNodeLowers.add(sequenceNode);
+ }
+ }
+ return sequenceNodeLowers;
+ }
+
+ /**
+ * Get all {@link ISequenceNode} of the current {@link SequenceDiagram} with
+ * range's including strictly timePoint.
+ *
+ * @param timePoint
+ * the timePoint from which get all {@link ISequenceNode}
+ * including it in their range
+ *
+ * @return the set of {@link ISequenceNode} having timePoint in their range,
+ * sorted by range from lower to upper
+ */
+ public Set<ISequenceNode> getAllSequenceNodesOn(int timePoint) {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ Preconditions.checkArgument(timePoint > 0, "timePoint must be strictly positive");
+
+ Set<ISequenceNode> sequenceNodeUnders = new TreeSet<ISequenceNode>(new RangeComparator());
+ for (ISequenceNode sequenceNode : getAllSequenceNodes()) {
+ Range sequenceEventRange = Range.verticalRange(sequenceNode.getBounds());
+ if (sequenceEventRange.includes(timePoint)) {
+ sequenceNodeUnders.add(sequenceNode);
+ }
+ }
+ return sequenceNodeUnders;
+ }
+
+ /**
+ * Get all {@link ISequenceNode} of the current {@link SequenceDiagram} with
+ * range's lowerbound strictly upper to timePoint.
+ *
+ * @param timePoint
+ * the timePoint from which get all upper {@link ISequenceNode}
+ *
+ * @return the set of {@link ISequenceNode} upper timePoint, sorted by range
+ * from lower to upper
+ */
+ public Set<ISequenceNode> getAllSequenceNodesUpperThan(int timePoint) {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ Preconditions.checkArgument(timePoint > 0, ASSERT_MESSAGE_ON_TIME_POINT);
+
+ Set<ISequenceNode> sequenceNodeUnders = new TreeSet<ISequenceNode>(new RangeComparator());
+ for (ISequenceNode sequenceNode : getAllSequenceNodes()) {
+ Range sequenceNodeRange = Range.verticalRange(sequenceNode.getBounds());
+ if (sequenceNodeRange.getLowerBound() > timePoint) {
+ sequenceNodeUnders.add(sequenceNode);
+ }
+ }
+ return sequenceNodeUnders;
+ }
+
+ /**
+ * Get all {@link ISequenceNode} of the current {@link SequenceDiagram}.
+ *
+ * @return the set of {@link ISequenceNode} of the current
+ * {@link SequenceDiagram}, sorted by range from lower to upper
+ */
+ public Set<ISequenceNode> getAllSequenceNodes() {
+ Preconditions.checkNotNull(sequenceDiagram, "contextual SequenceDiagram can't be null");
+
+ Set<ISequenceNode> allSequenceNodes = new TreeSet<ISequenceNode>(new RangeComparator());
+ allSequenceNodes.addAll(sequenceDiagram.getAllInstanceRoles());
+ allSequenceNodes.addAll(sequenceDiagram.getAllLifelines());
+ allSequenceNodes.addAll(sequenceDiagram.getAllAbstractNodeEvents());
+ allSequenceNodes.addAll(sequenceDiagram.getAllInteractionUses());
+ allSequenceNodes.addAll(sequenceDiagram.getAllCombinedFragments());
+ allSequenceNodes.addAll(sequenceDiagram.getAllOperands());
+ allSequenceNodes.addAll(sequenceDiagram.getAllEndOfLifes());
+ return allSequenceNodes;
+ }
+
+ /**
+ * Get the initial time from which event ends can graphically start. This
+ * initial time corresponds to y coordinate of the bottom of the biggest
+ * InstanceRole not connected to a Create message +
+ * {@link LayoutConstants#TIME_START_OFFSET}.
+ *
+ * @return the initial time if the current {@link SequenceDiagram} contains
+ * {@link Lifeline}, 0 else
+ */
+ public int getInitialTime() {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ int initialTime = 0;
+ for (Lifeline lifeline : sequenceDiagram.getAllLifelines()) {
+ int initialTimeCandidate = lifeline.getVerticalRange().getLowerBound();
+ if (initialTimeCandidate > initialTime && !lifeline.getInstanceRole().isExplicitlyCreated()) {
+ initialTime = initialTimeCandidate;
+ }
+ }
+ return initialTime + LayoutConstants.TIME_START_OFFSET + IBorderItemOffsets.DEFAULT_OFFSET.height;
+ }
+
+ /**
+ * Get the final time until which event ends can graphically end. This final
+ * time corresponds to y coordinate of the bottom of {@link Lifeline} -
+ * {@link LayoutConstants#TIME_STOP_OFFSET}.
+ *
+ * @return the final time if the current {@link SequenceDiagram} contains
+ * {@link Lifeline}, 0 else
+ */
+ public int getFinalTime() {
+ Preconditions.checkNotNull(sequenceDiagram, ASSERT_MESSAGE_ON_SEQUENCE_DIAGRAM);
+ int finalTime = 0;
+ if (!sequenceDiagram.getAllLifelines().isEmpty()) {
+ Lifeline lifeline = sequenceDiagram.getAllLifelines().iterator().next();
+ finalTime = lifeline.getVerticalRange().getUpperBound() - LayoutConstants.TIME_STOP_OFFSET;
+ }
+ return finalTime;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceMessageViewQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceMessageViewQuery.java
new file mode 100644
index 0000000000..ad69802617
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceMessageViewQuery.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import com.google.common.base.Preconditions;
+
+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.VerticalRangeFunction;
+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.Lifeline;
+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.util.Range;
+
+/**
+ * Queries on sequence messages (all kinds).
+ *
+ * @author pcdavid
+ */
+public class SequenceMessageViewQuery {
+ /**
+ * The message to query.
+ */
+ private final Edge edge;
+
+ /**
+ * Constructor.
+ *
+ * @param edge
+ * the message to query.
+ */
+ public SequenceMessageViewQuery(Edge edge) {
+ Preconditions.checkArgument(Message.notationPredicate().apply(edge));
+ this.edge = edge;
+ }
+
+ /**
+ * Tests whether this a reflective message, i.e. both its source and target
+ * are in the context of the same lifeline.
+ *
+ * @return <code>true</code> if this message is reflective.
+ */
+ public boolean isReflective() {
+ Option<Node> optSource = getSourceLifeline();
+ Option<Node> optTarget = getTargetLifeline();
+ return optSource.some() && optTarget.some() && optSource.get() == optTarget.get();
+ }
+
+ /**
+ * Returns the lifeline in the context of which this message is sent.
+ *
+ * @return the lifeline in the context of which this message is sent.
+ */
+ public Option<Node> getSourceLifeline() {
+ Option<Node> result = Options.newNone();
+ View source = edge.getSource();
+ Option<ISequenceElement> iSequenceElement = ISequenceElementAccessor.getISequenceElement(source);
+ if (iSequenceElement.some()) {
+ Option<Lifeline> lifeline = iSequenceElement.get().getLifeline();
+ if (lifeline.some()) {
+ result = Options.newSome(lifeline.get().getNotationNode());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the lifeline in the context of which this message is received.
+ *
+ * @return the lifeline in the context of which this message is received.
+ */
+ public Option<Node> getTargetLifeline() {
+ Option<Node> result = Options.newNone();
+ View target = edge.getTarget();
+ Option<ISequenceElement> iSequenceElement = ISequenceElementAccessor.getISequenceElement(target);
+ if (iSequenceElement.some()) {
+ Option<Lifeline> lifeline = iSequenceElement.get().getLifeline();
+ if (lifeline.some()) {
+ result = Options.newSome(lifeline.get().getNotationNode());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the vertical range of the message.
+ *
+ * @return the vertical range of the message.
+ */
+ public Range getVerticalRange() {
+ Range result;
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+ if (bendpoints == null || bendpoints.getPoints().isEmpty()) {
+ result = Range.emptyRange();
+ } else {
+ int firstY = getFirstPointVerticalPosition(true);
+ if (isLogicallyInstantaneous()) {
+ if (validateFirstPointStability(firstY)) {
+ result = new Range(firstY, firstY);
+ } else {
+ int lastY = getLastPointVerticalPosition(false);
+ result = new Range(lastY, lastY);
+ }
+ } else {
+ int lastY = getLastPointVerticalPosition(false);
+ if (msgToSelfInvalidEndLocation(edge.getSource(), edge.getTarget())) {
+ firstY = VerticalRangeFunction.INSTANCE.apply(edge.getSource()).getUpperBound();
+ lastY = firstY + LayoutConstants.MESSAGE_TO_SELF_BENDPOINT_VERTICAL_GAP;
+ }
+ result = new Range(Math.min(firstY, lastY), Math.max(firstY, lastY));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Use only to check stability. Returns the vertical range of the message
+ * calculated with anchor position from source or from target.
+ *
+ * @param source
+ * anchor selection for range computation.
+ * @return the vertical range of the message from source or target, as
+ * requested.
+ */
+ public Range getVerticalRange(boolean source) {
+ Range result;
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+ if (bendpoints == null || bendpoints.getPoints().isEmpty()) {
+ result = Range.emptyRange();
+ } else {
+ int firstY = getFirstPointVerticalPosition(source);
+ int lastY = getLastPointVerticalPosition(source);
+ result = new Range(Math.min(firstY, lastY), Math.max(firstY, lastY));
+ }
+ return result;
+ }
+
+ /**
+ * FIXME this workaround should be remove when business rules will be move from
+ * sequence ui to sequence core. This workaround is needed when dropping an
+ * execution on messages that will be reconnected.
+ *
+ * @param firstY
+ * the vertical position of the first bendpoint
+ * @return if the range should be calculated with the other end of the
+ * message.
+ */
+ private boolean validateFirstPointStability(int firstY) {
+ // if (getSource() instanceof ISequenceEvent) {
+ // ISequenceEvent ise = (ISequenceEvent) getSource();
+ // Edge edge = (Edge) this.getNotationView();
+ // // Validate that the edge notation source is the same as the SMEP
+ // source notation
+ // return
+ // edge.getSource().getElement().equals(ise.resolveSemanticElement());
+ // }
+ return true;
+ }
+
+ /**
+ * .
+ *
+ * @param source
+ * .
+ * @return .
+ */
+ public int getFirstPointVerticalPosition(boolean source) {
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+ RelativeBendpoint firstPoint = (RelativeBendpoint) bendpoints.getPoints().get(0);
+ return getPointVerticalPosition(firstPoint, source);
+ }
+
+ /**
+ *
+ * @param otherEnd
+ * @return
+ */
+ private boolean msgToSelfInvalidEndLocation(View end, View otherEnd) {
+ // FIXME
+ // if (SequenceDiagramNotationHelper.isSequenceEvent(end)) {
+ // if (isReflective() && otherEnd != null) {
+ // if (EcoreUtil.isAncestor(otherEnd, end)) {
+ // return true;
+ //
+ // }
+ // // Point location = ((ISequenceEvent)
+ // // end).getFigure().getBounds().getLocation();
+ // // return location.x == 0 && location.y == 0;
+ // }
+ // }
+ return false;
+ }
+
+ /**
+ * .
+ *
+ * @param source
+ * .
+ * @return .
+ */
+ public int getLastPointVerticalPosition(boolean source) {
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+ RelativeBendpoint lastPoint = (RelativeBendpoint) bendpoints.getPoints().get(bendpoints.getPoints().size() - 1);
+ return getPointVerticalPosition(lastPoint, source);
+ }
+
+ /**
+ * .
+ *
+ * @param bendpoint
+ * .
+ * @param source
+ * .
+ * @return .
+ */
+ public int getPointVerticalPosition(RelativeBendpoint bendpoint, boolean source) {
+ int verticalPosition = 0;
+ if (!source) {
+ int tgtRefY = getTargetAnchorVerticalPosition();
+ verticalPosition = tgtRefY + bendpoint.getTargetY();
+ } else {
+ int srcRefY = getSourceAnchorVerticalPosition();
+ verticalPosition = srcRefY + bendpoint.getSourceY();
+ }
+ return verticalPosition;
+ }
+
+ /**
+ * .
+ *
+ * @return .
+ */
+ public int getSourceAnchorVerticalPosition() {
+ IdentityAnchor srcAnchor = (IdentityAnchor) edge.getSourceAnchor();
+ Range sourceRange = new SequenceNodeQuery((Node) edge.getSource()).getVerticalRange();
+ return getAnchorAbsolutePosition(srcAnchor, sourceRange);
+ // could not return 0 : other utility methode take 0,5 precision point
+ // for null anchor.
+ // return 0;
+ }
+
+ /**
+ * Should not be called if !(getTarget() instanceof ISequenceEvent).
+ *
+ * @return target anchor absolute position.
+ */
+ public int getTargetAnchorVerticalPosition() {
+ IdentityAnchor tgtAnchor = (IdentityAnchor) edge.getTargetAnchor();
+ if (edge.getTarget() instanceof Node) {
+ Range targetRange = new SequenceNodeQuery((Node) edge.getTarget()).getVerticalRange();
+ return getAnchorAbsolutePosition(tgtAnchor, targetRange);
+ }
+ return getSourceAnchorVerticalPosition();
+ // could not return 0 : other utility methode take 0,5 precision point
+ // for null anchor.
+ // return 0;
+ }
+
+ private int getAnchorAbsolutePosition(IdentityAnchor anchor, Range range) {
+ double relY = anchor != null ? parseRelY(anchor.getId()) : 0.5;
+ return range.getLowerBound() + (int) Math.round(relY * range.width());
+ }
+
+ private double parseRelY(String terminal) {
+ try {
+ return Float.parseFloat(terminal.substring(terminal.indexOf(',') + 1, terminal.indexOf(')')));
+ } catch (NumberFormatException e) {
+ return Double.NaN;
+ }
+ }
+
+ private boolean isLogicallyInstantaneous() {
+ return !isReflective();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceNodeQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceNodeQuery.java
new file mode 100644
index 0000000000..67b551eeee
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/SequenceNodeQuery.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.Size;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.WorkspaceImage;
+import org.eclipse.sirius.diagram.business.internal.query.DNodeQuery;
+import org.eclipse.sirius.diagram.internal.refresh.GMFHelper;
+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.Lifeline;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IBorderItemOffsets;
+
+/**
+ * Queries on sequence elements which are represented by GMF nodes.
+ *
+ * @author pcdavid
+ */
+public class SequenceNodeQuery {
+
+ private final Node node;
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * the node to query.
+ */
+ public SequenceNodeQuery(Node node) {
+ this.node = node;
+ }
+
+ /**
+ * Returns the vertical range of a sequence diagram element from its GMF
+ * notation node.
+ *
+ * @return the vertical range of the element.
+ */
+ public Range getVerticalRange() {
+ EObject element = node.getElement();
+ if (!(element instanceof DDiagramElement)) {
+ return null;
+ } else {
+ Rectangle absoluteBounds = GMFHelper.getAbsoluteBounds(node);
+ int y = absoluteBounds.y;
+ int height = absoluteBounds.height;
+ // GMFHelper.getAbsoluteBounds() use default
+ // DDiagramElementContainer (DNodeContainer/DNodeList) dimension if
+ // size == (-1,-1) and here we need to have the real GMF size if ==
+ // to (-1,-1)
+ if (node.getLayoutConstraint() instanceof Size) {
+ Size size = (Size) node.getLayoutConstraint();
+ height = size.getHeight();
+ }
+ // handle container auto size -> range.widht = 0, next layout will
+ // set the good value
+ // check in interaction use view factory, that it cannot be there
+ if (element instanceof DNodeContainer && height == -1) {
+ height = 0;
+ }
+ if (height == -1 && element instanceof DNode && ((DNode) element).getOwnedStyle() instanceof WorkspaceImage) {
+ height = new DNodeQuery((DNode) element).getDefaultDimension().height;
+ }
+
+ Range result = new Range(y, y + height);
+
+ if (isShifted()) {
+ result = result.shifted(IBorderItemOffsets.DEFAULT_OFFSET.height);
+ }
+
+ return result;
+ }
+ }
+
+ private boolean isShifted() {
+ return Lifeline.notationPredicate().apply(node) || AbstractNodeEvent.notationPredicate().apply(node) || EndOfLife.notationPredicate().apply(node);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/TSequenceDiagramQuery.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/TSequenceDiagramQuery.java
new file mode 100644
index 0000000000..4f6b7672cb
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/query/TSequenceDiagramQuery.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.business.internal.query;
+
+import java.util.Iterator;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+
+import org.eclipse.sirius.diagram.sequence.template.TBasicMessageMapping;
+import org.eclipse.sirius.diagram.sequence.template.TExecutionMapping;
+import org.eclipse.sirius.diagram.sequence.template.TLifelineMapping;
+import org.eclipse.sirius.diagram.sequence.template.TSequenceDiagram;
+
+/**
+ * Queries starting from a {@link TSequenceDiagram}.
+ *
+ * @author cbrun
+ *
+ */
+public class TSequenceDiagramQuery {
+
+ private TSequenceDiagram template;
+
+ /**
+ * Create a new query.
+ *
+ * @param template
+ * starting point of the query.
+ */
+ public TSequenceDiagramQuery(TSequenceDiagram template) {
+ this.template = template;
+ }
+
+ /**
+ * return any Lifeline Mapping having the given name.
+ *
+ * @param name
+ * name of the element to find.
+ * @return any Lifeline Mapping having the given name.
+ */
+ public Iterator<TLifelineMapping> getLifeLineMappings(final String name) {
+ return Iterators.filter(Iterators.filter(template.eAllContents(), TLifelineMapping.class), new Predicate<TLifelineMapping>() {
+
+ public boolean apply(TLifelineMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+
+ /**
+ * return any {@link TExecutionMapping} Mapping having the given name.
+ *
+ * @param name
+ * name of the element to find.
+ * @return any TExecutionMapping Mapping having the given name.
+ */
+ public Iterator<TExecutionMapping> getExecutionMappings(final String name) {
+ return Iterators.filter(Iterators.filter(template.eAllContents(), TExecutionMapping.class), new Predicate<TExecutionMapping>() {
+
+ public boolean apply(TExecutionMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+
+ /**
+ * return any {@link TBasicMessageMapping} Mapping having the given name.
+ *
+ * @param name
+ * name of the element to find.
+ * @return any TBasicMessageMapping Mapping having the given name.
+ */
+ public Iterator<TBasicMessageMapping> getBasicMessageMapping(final String name) {
+ return Iterators.filter(Iterators.filter(template.eAllContents(), TBasicMessageMapping.class), new Predicate<TBasicMessageMapping>() {
+
+ public boolean apply(TBasicMessageMapping input) {
+ return name.equals(input.getName());
+ }
+
+ });
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/FixBendpointsOnCreationCommand.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/FixBendpointsOnCreationCommand.java
new file mode 100644
index 0000000000..76d2020f69
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/FixBendpointsOnCreationCommand.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Dimension;
+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.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.Routing;
+import org.eclipse.gmf.runtime.notation.Style;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.diagram.business.api.view.SiriusLayoutDataManager;
+import org.eclipse.sirius.diagram.business.internal.view.EdgeLayoutData;
+import org.eclipse.sirius.diagram.business.internal.view.LayoutData;
+import org.eclipse.sirius.diagram.internal.refresh.GMFHelper;
+import org.eclipse.sirius.diagram.internal.refresh.edge.SlidableAnchor;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IBorderItemOffsets;
+
+/**
+ * A Command to update sequence message bendpoints after the
+ * CanonicalSynchronizer.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class FixBendpointsOnCreationCommand extends RecordingCommand {
+
+ private Edge newEdge;
+
+ private View source;
+
+ private View target;
+
+ // Anchors
+ private String sourceTerminal;
+
+ private String targetTerminal;
+
+ // Bendpoints
+ private PointList pointList;
+
+ // Routing
+ private Routing routing;
+
+ /**
+ * Default constructor.
+ *
+ * @param domain
+ * the {@link TransactionalEditingDomain} on which execute this
+ * Command
+ *
+ * @param createdEdge
+ * the {@link Edge} for which update the bendpoints
+ */
+ public FixBendpointsOnCreationCommand(TransactionalEditingDomain domain, Edge createdEdge) {
+ super(domain);
+ this.newEdge = createdEdge;
+ }
+
+ /**
+ * Overridden to update the bendpoints of the specified {@link Edge}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+
+ this.source = newEdge.getSource();
+ this.target = newEdge.getTarget();
+
+ if (source != null && target != null) {
+
+ EObject element = newEdge.getElement();
+ if (element instanceof DEdge) {
+ DEdge dEdge = (DEdge) element;
+ updateEdge(dEdge);
+ }
+ }
+ }
+
+ private void updateEdge(DEdge dEdge) {
+
+ // Bendpoints
+ pointList = new PointList();
+ Point sourceRefPoint = new Point(0, 0);
+ Point targetRefPoint = new Point(0, 0);
+
+ EdgeLayoutData egdeLayoutData = null;
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(true);
+ try {
+ egdeLayoutData = SiriusLayoutDataManager.INSTANCE.getData(dEdge, false);
+ } finally {
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(false);
+ }
+ if (egdeLayoutData != null) {
+
+ sourceTerminal = egdeLayoutData.getSourceTerminal();
+ targetTerminal = egdeLayoutData.getTargetTerminal();
+
+ // pointList, sourceRefPoint, targetRefPoint of
+ // the edgeLayoutData can be null if the edge is
+ // hide when the layout data is stored
+ if (egdeLayoutData.getPointList() != null) {
+ pointList = egdeLayoutData.getPointList();
+ }
+ if (egdeLayoutData.getSourceRefPoint() != null) {
+ sourceRefPoint = egdeLayoutData.getSourceRefPoint();
+ }
+ if (egdeLayoutData.getTargetRefPoint() != null) {
+ targetRefPoint = egdeLayoutData.getTargetRefPoint();
+ }
+
+ routing = egdeLayoutData.getRouting();
+
+ } else {
+ computeEdgeDataWithoutEdgeLayoutData();
+ }
+
+ // Set connection anchors :
+ updateConnectionAnchors();
+
+ // Set Bendpoints :
+ updateBendpoints(sourceRefPoint, targetRefPoint);
+ }
+
+ private void computeEdgeDataWithoutEdgeLayoutData() {
+ Point firstClick = new Point(0, 0);
+ Rectangle sourceBounds = GMFHelper.getAbsoluteBounds((Node) source);
+ if (source.getElement() instanceof AbstractDNode) {
+ AbstractDNode sourceDNode = (AbstractDNode) source.getElement();
+ if (sourceDNode.eContainer() instanceof AbstractDNode) {
+ AbstractDNode parentDNode = (AbstractDNode) sourceDNode.eContainer();
+ if (parentDNode.getOwnedBorderedNodes().contains(sourceDNode)) {
+ sourceBounds.y += IBorderItemOffsets.DEFAULT_OFFSET.height;
+ sourceBounds.height += 5;
+ }
+ }
+ LayoutData sourceLayoutData = null;
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(true);
+ try {
+ sourceLayoutData = SiriusLayoutDataManager.INSTANCE.getData(sourceDNode);
+ } finally {
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(false);
+ }
+ if (sourceLayoutData == null) {
+ firstClick = sourceBounds.getCenter();
+ } else {
+ Point sourceLocation = sourceLayoutData.getLocation();
+ firstClick = sourceLocation;
+ }
+ }
+
+ PrecisionPoint sourceRelativeLocation = BaseSlidableAnchor.getAnchorRelativeLocation(firstClick, sourceBounds);
+ sourceTerminal = "(" + sourceRelativeLocation.preciseX + "," + sourceRelativeLocation.preciseY + ")";
+
+ Point secondClick = new Point(0, 0);
+ Rectangle targetBounds = GMFHelper.getAbsoluteBounds((Node) target);
+
+ if (target.getElement() instanceof AbstractDNode) {
+ AbstractDNode targetDNode = (AbstractDNode) target.getElement();
+ if (targetDNode.eContainer() instanceof AbstractDNode) {
+ AbstractDNode parentDNode = (AbstractDNode) targetDNode.eContainer();
+ if (parentDNode.getOwnedBorderedNodes().contains(targetDNode)) {
+ targetBounds.y += IBorderItemOffsets.DEFAULT_OFFSET.height;
+ targetBounds.height += 5;
+ }
+ }
+ LayoutData targetLayoutData = null;
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(true);
+ try {
+ targetLayoutData = SiriusLayoutDataManager.INSTANCE.getData(targetDNode);
+ } finally {
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(false);
+ }
+
+ if (targetLayoutData == null) {
+ secondClick = targetBounds.getCenter();
+ } else {
+ Point targetLocation = targetLayoutData.getLocation();
+ secondClick = targetLocation;
+ }
+ }
+
+ PrecisionPoint targetRelativeLocation = BaseSlidableAnchor.getAnchorRelativeLocation(secondClick, targetBounds);
+ targetTerminal = "(" + targetRelativeLocation.preciseX + "," + targetRelativeLocation.preciseY + ")";
+
+ // Computes pointList
+ PrecisionPoint sourceRelativeReference = SequenceSlidableAnchor.parseTerminalString(sourceTerminal);
+ SlidableAnchor sourceAnchor = new SequenceSlidableAnchor((Node) source, sourceRelativeReference);
+ pointList.addPoint(sourceAnchor.getLocation(sourceAnchor.getReferencePoint()));
+
+ PrecisionPoint targetRelativeReference = SequenceSlidableAnchor.parseTerminalString(targetTerminal);
+ SlidableAnchor targetAnchor = new SequenceSlidableAnchor((Node) target, targetRelativeReference);
+ pointList.addPoint(targetAnchor.getLocation(targetAnchor.getReferencePoint()));
+ }
+
+ private void updateConnectionAnchors() {
+ if (sourceTerminal != null) {
+ if (sourceTerminal.length() == 0)
+ newEdge.setSourceAnchor(null);
+ else {
+ IdentityAnchor a = (IdentityAnchor) newEdge.getSourceAnchor();
+ if (a == null)
+ a = NotationFactory.eINSTANCE.createIdentityAnchor();
+ a.setId(sourceTerminal);
+ newEdge.setSourceAnchor(a);
+ }
+ }
+ if (targetTerminal != null) {
+ if (targetTerminal.length() == 0)
+ newEdge.setTargetAnchor(null);
+ else {
+ IdentityAnchor a = (IdentityAnchor) newEdge.getTargetAnchor();
+ if (a == null)
+ a = NotationFactory.eINSTANCE.createIdentityAnchor();
+ a.setId(targetTerminal);
+ newEdge.setTargetAnchor(a);
+ }
+
+ }
+ }
+
+ private void updateBendpoints(Point sourceRefPoint, Point targetRefPoint) {
+ List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>();
+ int numOfPoints = pointList.size();
+ for (short i = 0; i < numOfPoints; i++) {
+ Dimension s = pointList.getPoint(i).getDifference(sourceRefPoint);
+ Dimension t = pointList.getPoint(i).getDifference(targetRefPoint);
+ newBendpoints.add(new RelativeBendpoint(s.width, s.height, t.width, t.height));
+ }
+
+ RelativeBendpoints points = (RelativeBendpoints) newEdge.getBendpoints();
+ points.setPoints(newBendpoints);
+
+ // Routing
+ if (routing != null) {
+ Style routingStyle = newEdge.getStyle(NotationPackage.Literals.ROUTING_STYLE);
+ routingStyle.eSet(NotationPackage.Literals.ROUTING_STYLE__ROUTING, routing);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutCommand.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutCommand.java
new file mode 100644
index 0000000000..3dab7ec0df
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutCommand.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+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.ISequenceElementAccessor;
+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;
+
+/**
+ * Command to refresh the graphical layout of the whole diagram.
+ *
+ * @author edugueperoux
+ */
+public class RefreshLayoutCommand extends RecordingCommand {
+
+ private Diagram diagram;
+
+ private boolean refreshDiagram;
+
+ /**
+ * Default constructor.
+ *
+ * @param diagram
+ * {@link Diagram} to refresh, used also to access
+ * {@link SequenceDDiagram} & {@link SequenceDiagram} to refresh
+ *
+ * @param refreshDiagram
+ * <code>true</code> if we should actually update the GMF model
+ *
+ * {@inheritDoc}
+ */
+ public RefreshLayoutCommand(TransactionalEditingDomain domain, Diagram diagram, boolean refreshDiagram) {
+ super(domain, "Refresh graphical layout");
+ this.diagram = diagram;
+ this.refreshDiagram = refreshDiagram;
+ }
+
+ /**
+ * Overridden to refresh the sequence layout.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ SequenceDiagram sequenceDiagram = ISequenceElementAccessor.getSequenceDiagram(diagram).get();
+ SequenceDDiagram sequenceDDiagram = sequenceDiagram.getSequenceDDiagram();
+
+ /*
+ * Everything has been committed, so we should be in a stable state
+ * where it is safe to refresh both orderings.
+ */
+ AbstractModelChangeOperation<Void> refreshSemanticOrderingOperation = new RefreshSemanticOrderingsOperation(sequenceDDiagram);
+ refreshSemanticOrderingOperation.execute();
+ AbstractModelChangeOperation<Void> refreshGraphicalOrderingOperation = new RefreshGraphicalOrderingOperation(sequenceDiagram);
+ refreshGraphicalOrderingOperation.execute();
+
+ if (refreshDiagram) {
+ /*
+ * Launch a non-packing layout
+ */
+ AbstractModelChangeOperation<Void> synchronizeGraphicalOrderingOperation = new SynchronizeGraphicalOrderingOperation(diagram, false);
+ synchronizeGraphicalOrderingOperation.execute();
+ /*
+ * The layout has probably changed graphical positions: re-compute
+ * the ordering to make sure it is up-to-date.
+ */
+ refreshGraphicalOrderingOperation.execute();
+ }
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutScope.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutScope.java
new file mode 100644
index 0000000000..f6af464111
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutScope.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+
+import com.google.common.base.Predicate;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.WorkspaceImage;
+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.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.util.BendpointsHelper;
+import org.eclipse.sirius.diagram.sequence.util.NotificationQuery;
+
+/**
+ * Default refresh layout scope for sequence diagram. This predicate decides
+ * whether or not we need to refresh the graphical layout, i.e. launch a
+ * non-packing layout
+ *
+ * @author mporhel
+ */
+public class RefreshLayoutScope implements Predicate<Notification> {
+
+ private final Predicate<Notification> isLayoutConstraintNotationChange = new Predicate<Notification>() {
+ Object[] features = new Object[] { NotationPackage.eINSTANCE.getRelativeBendpoints_Points(), NotationPackage.eINSTANCE.getLocation_Y(), NotationPackage.eINSTANCE.getLocation_X(),
+ NotationPackage.eINSTANCE.getSize_Width(), NotationPackage.eINSTANCE.getSize_Height(), };
+
+ public boolean apply(Notification input) {
+ NotificationQuery nq = new NotificationQuery(input);
+ return nq.isNotationChange() && isLayout(input.getFeature()) && !input.isTouch();
+ }
+
+ private boolean isLayout(Object feature) {
+ for (Object feature2 : features) {
+ if (feature == feature2) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ private final Predicate<Notification> isSructuralNotationChange = new Predicate<Notification>() {
+ int[] types = new int[] { Notification.ADD, Notification.ADD_MANY, Notification.MOVE, Notification.REMOVE, Notification.REMOVE_MANY };
+
+ public boolean apply(Notification input) {
+ NotificationQuery nq = new NotificationQuery(input);
+ return nq.isNotationChange() && isStructural(input.getEventType());
+ }
+
+ private boolean isStructural(int eventType) {
+ for (int type : types) {
+ if (eventType == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean apply(Notification input) {
+ return needsLayout(input);
+ }
+
+ private boolean needsLayout(Notification notification) {
+ return !isLayoutTouch(notification) && (containsStructuralNotationChanges(notification) || containsLayoutConstraintNotationChanges(notification) || containsSetWkpImgApplication(notification));
+ }
+
+ private boolean containsLayoutConstraintNotationChanges(Notification notification) {
+ return isLayoutConstraintNotationChange.apply(notification);
+ }
+
+ private boolean containsStructuralNotationChanges(Notification notification) {
+
+ return isSructuralNotationChange.apply(notification);
+ }
+
+ private boolean isLayoutTouch(Notification notification) {
+ boolean result = true;
+
+ boolean isTouch = notification.isTouch();
+ if (!isTouch) {
+ if (NotationPackage.eINSTANCE.getRelativeBendpoints_Points().equals(notification.getFeature())) {
+ isTouch = BendpointsHelper.areSameBendpoints(notification.getOldValue(), notification.getNewValue());
+ }
+ }
+
+ if (!isTouch) {
+ result = false;
+ }
+
+ return result;
+ }
+
+ private boolean containsSetWkpImgApplication(Notification notification) {
+ boolean newStyle = false;
+ boolean wkpImageCustomization = false;
+ boolean wkpImageDeCustomization = false;
+
+ if (notification.getEventType() == Notification.SET && SiriusPackage.eINSTANCE.getDNode_OwnedStyle().equals(notification.getFeature()) && hasSequenceMapping(notification.getNotifier())) {
+ newStyle = true;
+ } else if (SiriusPackage.eINSTANCE.getCustomizable_CustomFeatures().equals(notification.getFeature()) && notification.getNotifier() instanceof WorkspaceImage) {
+ WorkspaceImage workspaceImage = (WorkspaceImage) notification.getNotifier();
+ wkpImageCustomization = !workspaceImage.getCustomFeatures().isEmpty();
+ wkpImageDeCustomization = !wkpImageCustomization;
+ }
+
+ return newStyle && (wkpImageCustomization || wkpImageDeCustomization);
+ }
+
+ private boolean hasSequenceMapping(Object notifier) {
+ if (notifier instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) notifier;
+ return AbstractNodeEvent.viewpointElementPredicate().apply(dde) || EndOfLife.viewpointElementPredicate().apply(dde) || InstanceRole.viewpointElementPredicate().apply(dde);
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutTrigger.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutTrigger.java
new file mode 100644
index 0000000000..e1e126789c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/RefreshLayoutTrigger.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.business.api.session.ModelChangeTrigger;
+
+/**
+ * Default refresh layout trigger for Sequence Diagram edit part.
+ *
+ * @author mporhel
+ */
+public class RefreshLayoutTrigger implements ModelChangeTrigger {
+
+ /**
+ * Priority of this {@link ModelChangeTrigger}.
+ */
+ private static final int REFRESH_LAYOUT_TRIGGER_PRIORITY = SequenceCanonicalSynchronizerAdapter.SEQUENCE_CANONICAL_REFRESH_PRIORITY + 1;
+
+ private Diagram sequenceDiagram;
+
+ /**
+ * Constructor.
+ *
+ * @param sequenceDiagram
+ * the sequence diagram to refresh.
+ */
+ public RefreshLayoutTrigger(Diagram sequenceDiagram) {
+ this.sequenceDiagram = sequenceDiagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int priority() {
+ return REFRESH_LAYOUT_TRIGGER_PRIORITY;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Option<Command> localChangesAboutToCommit(Collection<Notification> notifications) {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(sequenceDiagram);
+ if (sequenceDiagram == null || domain == null) {
+ return Options.newNone();
+ }
+ Command refreshLayoutCommand = new RefreshLayoutCommand(domain, sequenceDiagram, true);
+ return Options.newSome(refreshLayoutCommand);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapter.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapter.java
new file mode 100644
index 0000000000..2b4c4568cf
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapter.java
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+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.notify.Notification;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.command.SetCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+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 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.common.tools.api.util.Options;
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.CollapseFilter;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.business.api.session.ModelChangeTrigger;
+import org.eclipse.sirius.diagram.business.api.view.SiriusLayoutDataManager;
+import org.eclipse.sirius.diagram.business.internal.view.LayoutData;
+import org.eclipse.sirius.diagram.internal.refresh.listeners.FilterListener;
+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.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.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.SequenceDiagram;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+import org.eclipse.sirius.diagram.sequence.business.internal.operation.SetVerticalRangeOperation;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceElementQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.RangeComparator;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceDiagramQuery;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+/**
+ * {@link ModelChangeTrigger} which return a {@link Command} to be executed just
+ * a SynchronizeGMFModelCommand to correct y location of execution (Node) and
+ * bendpoints of message (Edge).
+ *
+ * @author edugueperoux
+ */
+public class SequenceCanonicalSynchronizerAdapter implements ModelChangeTrigger {
+
+ /**
+ * Priority of this {@link ModelChangeTrigger}.
+ */
+ public static final int SEQUENCE_CANONICAL_REFRESH_PRIORITY = FilterListener.COMPOSITE_FILTER_REFRESH_PRIORITY + 1;
+
+ /**
+ * Overridden to return a Command to adapt CanonicalSynchronizer work for
+ * sequence.
+ *
+ * {@inheritDoc}
+ */
+ public Option<Command> localChangesAboutToCommit(Collection<Notification> notifications) {
+ Option<Command> result;
+ CompoundCommand compoundCommand = new CompoundCommand();
+ for (Notification notification : notifications) {
+ Object newValue = notification.getNewValue();
+ if (SequenceCanonicalSynchronizerAdapterScope.isNotificationForNodeAdding(notification)) {
+ Node newNode = (Node) newValue;
+
+ cancelArrangeNewNodeCommandforSequenceDiagram(newNode);
+
+ Command fixSequenceNodeLowerBoundCmd = getFixSequenceNodeCreationRangeCmd(newNode);
+ if (fixSequenceNodeLowerBoundCmd != null) {
+ compoundCommand.append(fixSequenceNodeLowerBoundCmd);
+ }
+
+ } else if (SequenceCanonicalSynchronizerAdapterScope.isNotificationForEdgeAdding(notification)) {
+ Edge newEdge = (Edge) newValue;
+ Command fixBendpointsForSequenceMessageCmd = getFixBendpointsForSequenceMessageCmd(newEdge);
+ if (fixBendpointsForSequenceMessageCmd != null) {
+ compoundCommand.append(fixBendpointsForSequenceMessageCmd);
+ }
+ }
+ }
+ Command cmd = compoundCommand;
+ result = Options.newSome(cmd);
+ return result;
+ }
+
+ private void cancelArrangeNewNodeCommandforSequenceDiagram(Node newNode) {
+ Diagram diagram = newNode.getDiagram();
+ if (diagram != null && ISequenceElementAccessor.getSequenceDiagram(diagram).some()) {
+ Map<Diagram, Set<View>> viewToArrangeCenter = SiriusLayoutDataManager.INSTANCE.getCreatedViewWithCenterLayout();
+ Map<Diagram, Set<View>> viewToArrange = SiriusLayoutDataManager.INSTANCE.getCreatedViewsToLayout();
+
+ Set<View> set = viewToArrange.get(diagram);
+ if (set != null) {
+ set.clear();
+ }
+
+ Set<View> set2 = viewToArrangeCenter.get(diagram);
+ if (set2 != null) {
+ set2.clear();
+ }
+ }
+ }
+
+ private Command getFixSequenceNodeCreationRangeCmd(Node newNode) {
+ Command fixSequenceNodeLowerBoundCmd = null;
+ EObject element = newNode.getElement();
+ EObject eContainer = element.eContainer();
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(newNode);
+ if (eContainer instanceof AbstractDNode && ISequenceElementAccessor.getISequenceNode(newNode).some()) {
+ AbstractDNode containerDNode = (AbstractDNode) eContainer;
+ if (containerDNode.getOwnedBorderedNodes().contains(element) && element instanceof AbstractDNode) {
+ AbstractDNode borderedDNode = (AbstractDNode) element;
+ LayoutData layoutData = null;
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(true);
+ try {
+ layoutData = SiriusLayoutDataManager.INSTANCE.getData(borderedDNode, true);
+ } finally {
+ SiriusLayoutDataManager.INSTANCE.setIgnoreConsumeState(false);
+ }
+ if (layoutData != null) {
+ Point location = layoutData.getLocation();
+ int y = location.y;
+
+ fixSequenceNodeLowerBoundCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.LOCATION__Y, y);
+ Dimension size = layoutData.getSize();
+ if (size != null && newNode.getLayoutConstraint() instanceof Size) {
+ fixSequenceNodeLowerBoundCmd = addSetSizeCmd(fixSequenceNodeLowerBoundCmd, domain, size, newNode);
+ }
+ expandSimpleExecution(newNode, fixSequenceNodeLowerBoundCmd, domain, y);
+ } else {
+ fixSequenceNodeLowerBoundCmd = getFlaggedRangeApplicationCommand(newNode, domain);
+ }
+ } else {
+ // Set height of operand to -1 to have
+ // SequenceVerticalLayout set the size correctly
+ Option<Operand> operandOption = ISequenceElementAccessor.getOperand(newNode);
+ if (operandOption.some()) {
+ Command resetOperandHeightCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__HEIGHT, -1);
+ fixSequenceNodeLowerBoundCmd = resetOperandHeightCmd;
+ Command resetOperandWidthCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__WIDTH, -1);
+ fixSequenceNodeLowerBoundCmd = fixSequenceNodeLowerBoundCmd.chain(resetOperandWidthCmd);
+ }
+ }
+ } else {
+ // Set height of combined fragment to -1 to have
+ // SequenceVerticalLayout set the size correctly
+ Option<CombinedFragment> combinedFragmentOption = ISequenceElementAccessor.getCombinedFragment(newNode);
+ if (combinedFragmentOption.some() && ((Bounds) newNode.getLayoutConstraint()).getHeight() == LayoutConstants.DEFAULT_COMBINED_FRAGMENT_HEIGHT) {
+ Command resetCombinedFragmentHeightCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__HEIGHT, -1);
+ fixSequenceNodeLowerBoundCmd = resetCombinedFragmentHeightCmd;
+ Command resetCombinedFragmentWidthCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__WIDTH, -1);
+ fixSequenceNodeLowerBoundCmd = fixSequenceNodeLowerBoundCmd.chain(resetCombinedFragmentWidthCmd);
+ } else {
+ Option<InteractionUse> interactionUseOption = ISequenceElementAccessor.getInteractionUse(newNode);
+ if (interactionUseOption.some() && ((Bounds) newNode.getLayoutConstraint()).getHeight() == LayoutConstants.DEFAULT_INTERACTION_USE_HEIGHT) {
+ Command resetInteractionUseHeightCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__HEIGHT, -1);
+ fixSequenceNodeLowerBoundCmd = resetInteractionUseHeightCmd;
+ Command resetInteractionUseWidthCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__WIDTH, -1);
+ fixSequenceNodeLowerBoundCmd = fixSequenceNodeLowerBoundCmd.chain(resetInteractionUseWidthCmd);
+ }
+ }
+ }
+ return fixSequenceNodeLowerBoundCmd;
+ }
+
+ private Command addSetSizeCmd(Command globalCmd, TransactionalEditingDomain domain, Dimension size, Node newNode) {
+ Command result = null;
+ LayoutConstraint createdNodeLayoutConstraint = newNode.getLayoutConstraint();
+ if (createdNodeLayoutConstraint instanceof Size) {
+ int width = size.width;
+ int height = size.height;
+
+ if (newNode.getElement() instanceof DDiagramElement && new DDiagramElementQuery((DDiagramElement) newNode.getElement()).isCollapsed()) {
+ DDiagramElement dde = (DDiagramElement) newNode.getElement();
+ CollapseFilter filter = Iterables.filter(dde.getGraphicalFilters(), CollapseFilter.class).iterator().next();
+
+ Command setFilterHeightCmd = SetCommand.create(domain, filter, SiriusPackage.Literals.COLLAPSE_FILTER__HEIGHT, height);
+ Command setHeightCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__HEIGHT, height);
+ result = globalCmd.chain(setFilterHeightCmd);
+ result = result.chain(setHeightCmd);
+ } else {
+ Command setWidthCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__WIDTH, width);
+ Command setHeightCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__HEIGHT, height);
+ result = globalCmd.chain(setWidthCmd);
+ result = result.chain(setHeightCmd);
+ }
+ }
+ return result;
+ }
+
+ private Command getFlaggedRangeApplicationCommand(View newView, TransactionalEditingDomain domain) {
+ Command flagCommand = null;
+ Option<ISequenceEvent> ise = ISequenceElementAccessor.getISequenceEvent(newView);
+
+ if (ise.some()) {
+ Rectangle flag = new ISequenceElementQuery(ise.get()).getFlaggedAbsoluteBounds();
+
+ // Sequence Refresh extension could report an exisitng flag
+ // (external reparent, reconnect, ...)
+ if (flag.x == LayoutConstants.EXTERNAL_CHANGE_FLAG.x) {
+ Range flaggedRange = new Range(flag.y, flag.bottom());
+ flagCommand = CommandFactory.createRecordingCommand(domain, new SetVerticalRangeOperation(ise.get(), flaggedRange));
+
+ if (newView instanceof Node) {
+ LayoutConstraint newViewLC = ((Node) newView).getLayoutConstraint();
+ if (newViewLC instanceof Size) {
+ Command setWidthCmd = SetCommand.create(domain, newViewLC, NotationPackage.Literals.SIZE__WIDTH, flag.width);
+ flagCommand = flagCommand.chain(setWidthCmd);
+ }
+ }
+ }
+ }
+
+ return flagCommand;
+ }
+
+ /*
+ * Simple Execution creation implies that GMF Node at creation have a
+ * LayoutConstants.DEFAULT_EXECUTION_HEIGHT as minimum height and tries to
+ * take the maximum available space up to the next event.
+ */
+ private void expandSimpleExecution(Node newNode, Command fixSequenceNodeLowerBoundCmd, TransactionalEditingDomain domain, int y) {
+ Option<Execution> execOption = ISequenceElementAccessor.getExecution(newNode);
+ if (execOption.some() && newNode.getSourceEdges().isEmpty() && newNode.getTargetEdges().isEmpty()) {
+ Execution execution = execOption.get();
+ View parentView = (View) newNode.eContainer();
+ Option<ISequenceEvent> parentSequenceEvent = ISequenceElementAccessor.getISequenceEvent(parentView);
+ Range parentEventRange = null;
+ if (parentSequenceEvent.some()) {
+ parentEventRange = parentSequenceEvent.get().getVerticalRange();
+ }
+
+ int finalHeight = LayoutConstants.DEFAULT_EXECUTION_HEIGHT;
+
+ // At this step the location of the new create exection
+ // is not yet corrected, will be corrected by the above
+ // SetCommand
+ int lowerRange = y;
+ if (parentEventRange != null) {
+ lowerRange += parentEventRange.getLowerBound();
+ }
+ int upperRange = lowerRange + execution.getProperLogicalBounds().height;
+ // Doesn't take newly created execution into account
+ if (hasEventEndsAfterUpperRange(execution, lowerRange, Collections.<ISequenceEvent> singleton(execution))) {
+ int lowerBoundOfNextEventEnd = getRangeLimitOfNextEventEndOf(execution, lowerRange, Collections.<ISequenceEvent> singleton(execution));
+ int newUpperRange = lowerBoundOfNextEventEnd - LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ if (newUpperRange > upperRange) {
+ finalHeight = newUpperRange - lowerRange;
+ Command setExecHeightCmd = SetCommand.create(domain, newNode.getLayoutConstraint(), NotationPackage.Literals.SIZE__HEIGHT, finalHeight);
+ fixSequenceNodeLowerBoundCmd.chain(setExecHeightCmd);
+ }
+ }
+ }
+ }
+
+ private int getRangeLimitOfNextEventEndOf(Execution execution, int upperRange, Set<ISequenceEvent> sequenceEventToIgnores) {
+ SequenceDiagram sequenceDiagram = execution.getDiagram();
+ SequenceDDiagram sequenceDDiagram = sequenceDiagram.getSequenceDDiagram();
+ int rangeLimitOfNextEventEnd = 0;
+
+ EventEnd eventEndAfter = null;
+ VerticalPositionFunction vpf = new VerticalPositionFunction(sequenceDDiagram);
+ for (EventEnd end : sequenceDDiagram.getGraphicalOrdering().getEventEnds()) {
+ int pos = vpf.apply(end);
+ if (pos != VerticalPositionFunction.INVALID_POSITION && pos > upperRange) {
+ eventEndAfter = end;
+ break;
+ }
+ }
+ int parentBottomMargin = LayoutConstants.EXECUTION_CHILDREN_MARGIN;
+ if (eventEndAfter != null) {
+ rangeLimitOfNextEventEnd = new VerticalPositionFunction(sequenceDDiagram).apply(eventEndAfter);
+ } else {
+ rangeLimitOfNextEventEnd = upperRange + LayoutConstants.DEFAULT_EXECUTION_HEIGHT + parentBottomMargin;
+ }
+ return rangeLimitOfNextEventEnd;
+ }
+
+ private boolean hasEventEndsAfterUpperRange(Execution execution, int upperRange, Set<ISequenceEvent> sequenceEventToIgnores) {
+ SequenceDiagram sequenceDiagram = execution.getDiagram();
+ Lifeline lifeline = execution.getLifeline().get();
+ Set<ISequenceEvent> eventEndsAfterUpperRange = getEventEndsAfterUpperRange(sequenceDiagram, lifeline, upperRange, sequenceEventToIgnores);
+ Set<ISequenceEvent> eventEndsOnUpperRange = getEventEndsOnUpperRange(sequenceDiagram, lifeline, upperRange, sequenceEventToIgnores);
+ return !eventEndsAfterUpperRange.isEmpty() || !eventEndsOnUpperRange.isEmpty();
+ }
+
+ private Set<ISequenceEvent> getEventEndsAfterUpperRange(SequenceDiagram sequenceDiagram, Lifeline lifeline, int upperRange, Set<ISequenceEvent> sequenceEventToIgnores) {
+ Set<ISequenceEvent> eventEndsAfterUpperRange = new TreeSet<ISequenceEvent>(new RangeComparator());
+ Set<ISequenceEvent> allSequenceEventsInUpperRange = new SequenceDiagramQuery(sequenceDiagram).getAllSequenceEventsUpperThan(upperRange);
+ allSequenceEventsInUpperRange.removeAll(sequenceEventToIgnores);
+ eventEndsAfterUpperRange.addAll(Sets.filter(allSequenceEventsInUpperRange, Predicates.not(Predicates.instanceOf(Lifeline.class))));
+ return eventEndsAfterUpperRange;
+ }
+
+ private Set<ISequenceEvent> getEventEndsOnUpperRange(SequenceDiagram sequenceDiagram, Lifeline lifeline, int upperRange, Set<ISequenceEvent> sequenceEventToIgnores) {
+ Set<ISequenceEvent> eventEndsOnUpperRange = new TreeSet<ISequenceEvent>(new RangeComparator());
+ Set<ISequenceEvent> allSequenceEventsOnRange = new SequenceDiagramQuery(sequenceDiagram).getAllSequenceEventsOn(upperRange);
+ allSequenceEventsOnRange.removeAll(sequenceEventToIgnores);
+ eventEndsOnUpperRange.addAll(Sets.filter(allSequenceEventsOnRange, Predicates.not(Predicates.instanceOf(Lifeline.class))));
+ return eventEndsOnUpperRange;
+ }
+
+ private Command getFixBendpointsForSequenceMessageCmd(final Edge newEdge) {
+ Command changeBendpointsCmd = null;
+ if (newEdge != null && ISequenceElementAccessor.getMessage(newEdge).some()) {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(newEdge);
+ changeBendpointsCmd = new FixBendpointsOnCreationCommand(domain, newEdge);
+ changeBendpointsCmd = changeBendpointsCmd.chain(getFlaggedRangeApplicationCommand(newEdge, domain));
+ }
+ return changeBendpointsCmd;
+ }
+
+ /**
+ * Overridden to specify a priority upper than
+ * {@link CollapseFilterListener#COLLAPSE_FILTER_REFRESH_PRIORITY} to be
+ * executed after it.
+ *
+ * {@inheritDoc}
+ */
+ public int priority() {
+ return SEQUENCE_CANONICAL_REFRESH_PRIORITY;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapterScope.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapterScope.java
new file mode 100644
index 0000000000..fbec0abdaf
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceCanonicalSynchronizerAdapterScope.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Predicate to notify SequenceCanonicalSynchronizerAdapter only for adding of
+ * GMF View.
+ *
+ * @author edugueperoux
+ */
+public class SequenceCanonicalSynchronizerAdapterScope implements Predicate<Notification> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean apply(Notification notification) {
+ return isNotificationForNodeAdding(notification) || isNotificationForEdgeAdding(notification);
+ }
+
+ /**
+ * Checks if this notification is about a add of a {@link Node} to the
+ * parent {@link Node}.
+ *
+ * @param notification
+ * {@link Notification} to check
+ *
+ * @return true if this notification is about a add of a {@link Node} to the
+ * parent {@link Node}
+ */
+ public static boolean isNotificationForNodeAdding(Notification notification) {
+ boolean isNotificationForNodeAdding = false;
+ Object newValue = notification.getNewValue();
+ Object feature = notification.getFeature();
+ isNotificationForNodeAdding = NotationPackage.Literals.VIEW__PERSISTED_CHILDREN.equals(feature) && Notification.ADD == notification.getEventType() && newValue instanceof Node
+ && isNotANote(newValue);
+ return isNotificationForNodeAdding;
+ }
+
+ /**
+ * Test that newValue is not a GMF Shape which represents a Note.
+ *
+ * @param newValue
+ * the object to test
+ *
+ * @return true if newValue is not a GMF Shape which represents a Note,
+ * false else
+ */
+ private static boolean isNotANote(Object newValue) {
+ return ((Node) newValue).getElement() != null;
+ }
+
+ /**
+ * Checks if this notification is about a add of a {@link Edge} to the
+ * parent {@link org.eclipse.gmf.runtime.notation.Diagram.Diagram}.
+ *
+ * @param notification
+ * {@link Notification} to check
+ *
+ * @return true if this notification is about a add of a {@link Edge} to the
+ * parent {@link org.eclipse.gmf.runtime.notation.Diagram}
+ */
+ public static boolean isNotificationForEdgeAdding(Notification notification) {
+ boolean isNotificationForEdgeAdding = false;
+ Object newValue = notification.getNewValue();
+ Object feature = notification.getFeature();
+ isNotificationForEdgeAdding = NotationPackage.Literals.DIAGRAM__PERSISTED_EDGES.equals(feature) && Notification.ADD == notification.getEventType() && newValue instanceof Edge;
+ return isNotificationForEdgeAdding;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtension.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtension.java
new file mode 100644
index 0000000000..ca4d6cc31c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtension.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+
+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.Maps;
+
+import org.eclipse.sirius.AbsoluteBoundsFilter;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.SiriusFactory;
+import org.eclipse.sirius.business.api.refresh.IRefreshExtension;
+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.Message;
+import org.eclipse.sirius.diagram.sequence.business.internal.layout.LayoutConstants;
+
+/**
+ * Specific refresh extension to handle structural changes in sequence diagrams.
+ * It allows to keep the last known position when the parent of an abstract node
+ * event changes.
+ *
+ * @author mporhel
+ *
+ */
+public class SequenceRefreshExtension implements IRefreshExtension {
+
+ private SequenceDDiagram currentDiagram;
+
+ private Map<EObject, AbsoluteBoundsFilter> flags;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeRefresh(DDiagram dDiagram) {
+ if (dDiagram instanceof SequenceDDiagram) {
+ currentDiagram = (SequenceDDiagram) dDiagram;
+
+ Collection<DDiagramElement> nodeEvents = getEventsToSync(currentDiagram);
+
+ if (nodeEvents.size() != 0) {
+ flags = Maps.newHashMapWithExpectedSize(nodeEvents.size());
+ for (DDiagramElement elt : nodeEvents) {
+ Iterable<AbsoluteBoundsFilter> flag = Iterables.filter(elt.getGraphicalFilters(), AbsoluteBoundsFilter.class);
+ EObject semanticTarget = elt.getTarget();
+ if (semanticTarget != null && Iterables.size(flag) == 1) {
+ flags.put(semanticTarget, Iterables.getOnlyElement(flag));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void postRefresh(DDiagram dDiagram) {
+ if (currentDiagram != null && currentDiagram.equals(dDiagram) && flags != null) {
+ Collection<DDiagramElement> nodeEvents = getEventsToSync((SequenceDDiagram) dDiagram);
+
+ if (nodeEvents.size() != 0) {
+ for (DDiagramElement elt : nodeEvents) {
+ Iterable<AbsoluteBoundsFilter> flag = Iterables.filter(elt.getGraphicalFilters(), AbsoluteBoundsFilter.class);
+ EObject semanticTarget = elt.getTarget();
+ if (semanticTarget != null && Iterables.isEmpty(flag) && flags.containsKey(semanticTarget)) {
+ AbsoluteBoundsFilter prevFlag = flags.get(semanticTarget);
+
+ AbsoluteBoundsFilter newFlag = SiriusFactory.eINSTANCE.createAbsoluteBoundsFilter();
+ newFlag.setX(LayoutConstants.EXTERNAL_CHANGE_FLAG.x);
+ newFlag.setY(prevFlag.getY());
+ newFlag.setHeight(prevFlag.getHeight());
+ newFlag.setWidth(prevFlag.getWidth());
+
+ elt.getGraphicalFilters().add(newFlag);
+ }
+ }
+ }
+ }
+ if (flags != null) {
+ flags.clear();
+ flags = null;
+ }
+ currentDiagram = null;
+ }
+
+ private Collection<DDiagramElement> getEventsToSync(SequenceDDiagram sdd) {
+ Collection<DDiagramElement> diagramElements = Lists.newArrayList(sdd.getDiagramElements());
+ Predicate<DDiagramElement> eventsToSync = Predicates.or(AbstractNodeEvent.viewpointElementPredicate(), Message.viewpointElementPredicate());
+ return Lists.newArrayList(Iterables.filter(diagramElements, eventsToSync));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtensionProvider.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtensionProvider.java
new file mode 100644
index 0000000000..91635915f4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceRefreshExtensionProvider.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.refresh.IRefreshExtension;
+import org.eclipse.sirius.business.api.refresh.IRefreshExtensionProvider;
+import org.eclipse.sirius.diagram.sequence.SequenceDDiagram;
+
+public class SequenceRefreshExtensionProvider implements IRefreshExtensionProvider {
+
+ private IRefreshExtension sequenceRefresh;
+
+ /**
+ * {@inheritDoc}
+ */
+ public IRefreshExtension getRefreshExtension(DDiagram viewPoint) {
+ if (sequenceRefresh == null) {
+ sequenceRefresh = new SequenceRefreshExtension();
+ }
+ return sequenceRefresh;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean provides(DDiagram viewPoint) {
+ return viewPoint instanceof SequenceDDiagram;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceSlidableAnchor.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceSlidableAnchor.java
new file mode 100644
index 0000000000..29578609d5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/refresh/SequenceSlidableAnchor.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.business.internal.refresh;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import org.eclipse.sirius.diagram.internal.refresh.edge.SlidableAnchor;
+
+/**
+ * Specialized anchor with some customizations for sequence diagrams.
+ *
+ * @author mporhel
+ */
+public class SequenceSlidableAnchor extends SlidableAnchor {
+
+ /**
+ * Constructor.
+ *
+ * @param owner
+ * the figure that this anchor is associated with.
+ * @param pp
+ * the PrecisionPoint that the anchor will initially attach to.
+ */
+ public SequenceSlidableAnchor(Node owner, PrecisionPoint pp) {
+ super(owner, pp);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Point getLocation(Point ownReference, Point foreignReference) {
+ return ownReference.getCopy();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/tool/ToolCommandBuilder.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/tool/ToolCommandBuilder.java
new file mode 100644
index 0000000000..e3bb822bd1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/tool/ToolCommandBuilder.java
@@ -0,0 +1,504 @@
+/*******************************************************************************
+ * 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.business.internal.tool;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+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.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+import com.google.common.collect.Maps;
+
+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.EdgeTarget;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.helper.task.InitInterpreterVariablesTask;
+import org.eclipse.sirius.business.api.helper.task.TaskHelper;
+import org.eclipse.sirius.business.api.query.IdentifiedElementQuery;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.description.tool.AbstractVariable;
+import org.eclipse.sirius.description.tool.ContainerCreationDescription;
+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.CombinedFragment;
+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.ordering.EventEndHelper;
+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.StateCreationTool;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.ExecutionCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.FrameCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.InstanceRoleCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.MessageCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.ObservationPointCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.OperandCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.SequenceGenericToolCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.SequencePaneBasedSelectionWizardCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.SequenceSelectionWizardCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.internal.tool.command.builders.StateCreationCommandBuilder;
+import org.eclipse.sirius.diagram.sequence.ordering.EventEnd;
+import org.eclipse.sirius.diagram.sequence.ordering.SingleEventEnd;
+import org.eclipse.sirius.diagram.tools.internal.commands.emf.EMFCommandFactoryUI;
+import org.eclipse.sirius.tools.api.command.SiriusCommand;
+import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
+import org.eclipse.sirius.tools.internal.command.builders.CommandBuilder;
+import org.eclipse.sirius.tools.internal.command.builders.NodeCreationCommandBuilder;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+
+/**
+ * Helper class to build the concrete commands executing the user-specified
+ * tools on specific parameters.
+ *
+ * @author pcdavid
+ */
+public final class ToolCommandBuilder {
+
+ private ToolCommandBuilder() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Builds the command which will execute the user-tasks specified operations
+ * to reorder an event.
+ *
+ * @param sequenceDDiagram
+ * the DRepresentation to use for the ModelOperations
+ * @param reorderTool
+ * the user-defined reordering tool.
+ * @param event
+ * the semantic element of the event which was moved.
+ * @param startingEndPredecessor
+ * the event end immediately preceding the reordered event's
+ * starting end after the move.
+ * @param finishingEndPredecessor
+ * the event end immediately preceding the reordered event's
+ * finishing end after the move.
+ * @return a command which executes the user-specified operations with the
+ * appropriate variables set.
+ */
+ public static SiriusCommand buildReorderCommand(SequenceDDiagram sequenceDDiagram, ReorderTool reorderTool, EObject event, EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor) {
+ ModelAccessor modelAccessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(event);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(event);
+
+ SiriusCommand result = new SiriusCommand(domain, new IdentifiedElementQuery(reorderTool).getLabel());
+ if (reorderTool.getOnEventMovedOperation().getFirstModelOperations() != null) {
+ result.getTasks().add(ToolCommandBuilder.buildVariablesInitializationTask(reorderTool, event, startingEndPredecessor, finishingEndPredecessor));
+ TaskHelper taskHelper = new TaskHelper(modelAccessor, new EMFCommandFactoryUI());
+
+ result.getTasks().add(taskHelper.buildTaskFromModelOperation(sequenceDDiagram, event, reorderTool.getOnEventMovedOperation().getFirstModelOperations()));
+ }
+ return result;
+ }
+
+ private static InitInterpreterVariablesTask buildVariablesInitializationTask(ReorderTool reorderTool, EObject event, EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor) {
+ Map<AbstractVariable, Object> variables = Maps.newHashMap();
+ variables.put(reorderTool.getStartingEndPredecessorAfter(), startingEndPredecessor);
+ variables.put(reorderTool.getFinishingEndPredecessorAfter(), finishingEndPredecessor);
+ return new InitInterpreterVariablesTask(variables, InterpreterUtil.getInterpreter(event), null);
+ }
+
+ /**
+ * Builds the command which will execute the user-tasks specified operations
+ * to reorder an instance role.
+ *
+ * @param sequenceDDiagram
+ * the DRepresentation to use for the ModelOperations
+ * @param reorderTool
+ * the user-defined instance role reordering tool.
+ * @param element
+ * the semantic element of the instance role which was moved.
+ * @param predecessorBefore
+ * the semantic element corresponding to the instance role
+ * immediately preceding the reordered instance role before the
+ * move.
+ * @param predecessorAfter
+ * the semantic element corresponding to the instance role
+ * immediately preceding the reordered instance role after the
+ * move.
+ * @return a command which executes the user-specified operations with the
+ * appropriate variables set.
+ */
+ public static SiriusCommand buildInstanceRoleReorderCommand(SequenceDDiagram sequenceDDiagram, InstanceRoleReorderTool reorderTool, EObject element, EObject predecessorBefore,
+ EObject predecessorAfter) {
+ ModelAccessor modelAccessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(element);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(element);
+
+ SiriusCommand result = new SiriusCommand(domain, new IdentifiedElementQuery(reorderTool).getLabel());
+ if (reorderTool.getInstanceRoleMoved().getFirstModelOperations() != null) {
+ result.getTasks().add(ToolCommandBuilder.buildVariablesInitializationTask(reorderTool, element, predecessorBefore, predecessorAfter));
+ TaskHelper taskHelper = new TaskHelper(modelAccessor, new EMFCommandFactoryUI());
+ result.getTasks().add(taskHelper.buildTaskFromModelOperation(sequenceDDiagram, element, reorderTool.getInstanceRoleMoved().getFirstModelOperations()));
+ }
+ return result;
+ }
+
+ private static InitInterpreterVariablesTask buildVariablesInitializationTask(InstanceRoleReorderTool reorderTool, EObject element, EObject predecessorBefore, EObject predecessorAfter) {
+ Map<AbstractVariable, Object> variables = Maps.newHashMap();
+ variables.put(reorderTool.getPredecessorBefore(), predecessorBefore);
+ variables.put(reorderTool.getPredecessorAfter(), predecessorAfter);
+ return new InitInterpreterVariablesTask(variables, InterpreterUtil.getInterpreter(element), null);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new message.
+ *
+ * @param source
+ * the source of the new message to create.
+ * @param target
+ * the target of the new message to create.
+ * @param tool
+ * the tool to use to create the message.
+ * @param startingEndBefore
+ * the event end which precedes graphically the source location
+ * of the new message, to be used by the tool do decide where to
+ * insert the message in the semantic model.
+ * @param finishingEndBefore
+ * the event end which precedes graphically the target location
+ * of the new message, to be used by the tool do decide where to
+ * insert the message in the semantic model.
+ * @return a command to create the message.
+ */
+ public static Command buildCreateMessageCommand(final EdgeTarget source, final EdgeTarget target, final MessageCreationTool tool, final EventEnd startingEndBefore,
+ final EventEnd finishingEndBefore) {
+ CommandBuilder builder = new MessageCreationCommandBuilder(tool, source, target, startingEndBefore, finishingEndBefore);
+ return getCommand(builder, source);
+ }
+
+ private static Command getCommand(CommandBuilder builder, EObject dObject) {
+ ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(dObject);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(dObject);
+ EMFCommandFactoryUI uiCallback = new EMFCommandFactoryUI();
+ builder.init(accessor, domain, uiCallback);
+ return builder.buildCommand();
+ }
+
+ private static Command getCommand(CommandBuilder builder, Session session) {
+ EMFCommandFactoryUI uiCallback = new EMFCommandFactoryUI();
+ builder.init(session.getModelAccessor(), session.getTransactionalEditingDomain(), uiCallback);
+ return builder.buildCommand();
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new instance role.
+ *
+ * @param diagram
+ * the sequence diagram on which to create the new instance role.
+ * @param tool
+ * the tool to use to create the instance role.
+ * @param predecessor
+ * the semantic element corresponding to the instance role
+ * graphically preceding the x location of the new instance role.
+ * @param location
+ * the clicked location.
+ * @return a command to create the instance role.
+ */
+ public static Command buildCreateInstanceRoleCommandFromTool(final DDiagram diagram, final InstanceRoleCreationTool tool, final EObject predecessor, Point location) {
+ CommandBuilder builder = new InstanceRoleCreationCommandBuilder(tool, diagram, predecessor, location);
+ return getCommand(builder, diagram);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new execution.
+ *
+ * @param node
+ * the node on which to create the new execution.
+ * @param tool
+ * the tool to use to create the execution.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new execution.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new execution.
+ * @param location
+ * the clicked location.
+ * @return a command to create the execution.
+ */
+ public static Command buildCreateExecutionCommandFromTool(final DNode node, final ExecutionCreationTool tool, final EventEnd startingEndPredecessor, final EventEnd finishingEndPredecessor,
+ Point location) {
+ CommandBuilder builder = new ExecutionCreationCommandBuilder(tool, node, startingEndPredecessor, finishingEndPredecessor, location);
+ Session session = SessionManager.INSTANCE.getSession(node.getTarget());
+ return getCommand(builder, session);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new observation point.
+ *
+ * @param diagramElement
+ * the clicked diagram element.
+ * @param tool
+ * the tool to use to create the execution.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new execution.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new execution.
+ * @return a command to create the execution.
+ */
+ public static Command buildCreateObservationPointCommandFromTool(final DDiagramElement diagramElement, final ObservationPointCreationTool tool, final EventEnd startingEndPredecessor,
+ final EventEnd finishingEndPredecessor) {
+ NodeCreationCommandBuilder builder = new ObservationPointCreationCommandBuilder(tool, diagramElement, startingEndPredecessor, finishingEndPredecessor);
+ Session session = SessionManager.INSTANCE.getSession(diagramElement.getTarget());
+ return getCommand(builder, session);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new observation point.
+ *
+ * @param diagram
+ * the diagram on which to create the new execution.
+ * @param tool
+ * the tool to use to create the execution.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new execution.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new execution.
+ * @return a command to create the execution.
+ */
+ public static Command buildCreateObservationPointCommandFromTool(final DDiagram diagram, final ObservationPointCreationTool tool, final EventEnd startingEndPredecessor,
+ final EventEnd finishingEndPredecessor) {
+ CommandBuilder builder = new ObservationPointCreationCommandBuilder(tool, diagram, startingEndPredecessor, finishingEndPredecessor);
+ return getCommand(builder, diagram);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new state.
+ *
+ * @param node
+ * the node on which to create the new state.
+ * @param tool
+ * the tool to use to create the state.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new state.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new state.
+ * @return a command to create the state.
+ */
+ public static Command buildCreateStateCommandFromTool(final DNode node, final StateCreationTool tool, final EventEnd startingEndPredecessor, final EventEnd finishingEndPredecessor) {
+ CommandBuilder builder = new StateCreationCommandBuilder(tool, node, startingEndPredecessor, finishingEndPredecessor);
+ Session session = SessionManager.INSTANCE.getSession(node.getTarget());
+ return getCommand(builder, session);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new interaction use.
+ *
+ * @param diagram
+ * the diagram on which to create the new IU.
+ * @param tool
+ * the tool to use to create the IU.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new IU.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new IU.
+ * @param coverage
+ * the semantic elements representing the lifelines graphically
+ * covered by the initial area of the IU.
+ * @return a command to create the IU.
+ */
+ public static Command buildCreateInteractionUseCommandFromTool(DDiagram diagram, InteractionUseCreationTool tool, EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor,
+ List<EObject> coverage) {
+ return ToolCommandBuilder.buildCreateFrameCommandFromTool(diagram, tool, startingEndPredecessor, finishingEndPredecessor, coverage);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new combined fragment.
+ *
+ * @param diagram
+ * the diagram on which to create the new CF.
+ * @param tool
+ * the tool to use to create the CF.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new CF.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new CF.
+ * @param coverage
+ * the semantic elements representing the lifelines graphically
+ * covered by the initial area of the CF.
+ * @return a command to create the CF.
+ */
+ public static Command buildCreateCombinedFragmentCommandFromTool(DDiagram diagram, CombinedFragmentCreationTool tool, EventEnd startingEndPredecessor, EventEnd finishingEndPredecessor,
+ List<EObject> coverage) {
+ return ToolCommandBuilder.buildCreateFrameCommandFromTool(diagram, tool, startingEndPredecessor, finishingEndPredecessor, coverage);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new combined fragment.
+ *
+ * @param diagram
+ * the diagram on which to create the new execution.
+ * @param tool
+ * the tool to use to create the combined fragment.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new CF.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new CF.
+ * @param coverage
+ * the semantic elements representing the lifelines graphically
+ * covered by the initial area of the CF.
+ * @return a command to create the execution.
+ */
+ private static Command buildCreateFrameCommandFromTool(DDiagram diagram, final ContainerCreationDescription tool, final EventEnd startingEndPredecessor, final EventEnd finishingEndPredecessor,
+ final List<EObject> coverage) {
+ CommandBuilder builder = new FrameCreationCommandBuilder(tool, diagram, startingEndPredecessor, finishingEndPredecessor, coverage);
+ return getCommand(builder, diagram);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations to
+ * create a new operand.
+ *
+ * @param nodeContainer
+ * the container in which to create the operand.
+ * @param tool
+ * the tool to use to create the operand.
+ * @param startingEndPredecessor
+ * the event end graphically preceding the starting position of
+ * the new Operand.
+ * @param finishingEndPredecessor
+ * the event end graphically preceding the finishing position of
+ * the new Operand.
+ * @return a command to create the execution.
+ */
+ public static org.eclipse.emf.common.command.Command buildCreateOperantCommandFromTool(DDiagramElementContainer nodeContainer, final OperandCreationTool tool,
+ final EventEnd startingEndPredecessor, final EventEnd finishingEndPredecessor) {
+ CommandBuilder builder = new OperandCreationCommandBuilder(tool, nodeContainer, startingEndPredecessor, finishingEndPredecessor);
+ Session session = SessionManager.INSTANCE.getSession(nodeContainer.getTarget());
+ return getCommand(builder, session);
+ }
+
+ /**
+ * Check if startingEndPredecessor is a starting {@link EventEnd} of
+ * {@link CombinedFragment}.
+ *
+ * @param sequenceDiagram
+ * the {@link SequenceDiagram} on which checks the property
+ * @param startingEndPredecessor
+ * the {@link EventEnd} to evaluate
+ * @return true if startingEndPredecessor is a starting {@link EventEnd} of
+ * {@link CombinedFragment}
+ */
+ public static boolean isStartingEventEndOfCombinedFragment(SequenceDiagram sequenceDiagram, EventEnd startingEndPredecessor) {
+ if (sequenceDiagram != null && startingEndPredecessor instanceof SingleEventEnd && ((SingleEventEnd) startingEndPredecessor).isStart()) {
+ ISequenceEvent ise = EventEndHelper.findISequenceEvent((SingleEventEnd) startingEndPredecessor, sequenceDiagram);
+ return ise instanceof CombinedFragment;
+ }
+ return false;
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations with
+ * a generic tool.
+ *
+ * @param containerView
+ * the clicked diagram element.
+ * @param tool
+ * the generic tool.
+ * @param endBefore
+ * the event end graphically preceding the position
+ * @param location
+ * the clicked location.
+ * @param diagram
+ * the GMF {@link Diagram}
+ * @return a command to execute the tool.
+ */
+ public static Command buildSequenceGenericToolCommandFromTool(EObject containerView, ToolDescription tool, EventEnd endBefore, Point location, Diagram diagram) {
+ CommandBuilder builder = new SequenceGenericToolCommandBuilder(tool, containerView, endBefore, location, diagram);
+ return getCommand(builder, containerView);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations with
+ * a pane based selection tool.
+ *
+ * @param tool
+ * the pane based selection tool.
+ * @param dContainer
+ * the clicked diagram element.
+ * @param selectedElement
+ * the selected elements
+ * @param endBefore
+ * the event end graphically preceding the position
+ * @param location
+ * the clicked location.
+ * @return a command to execute the tool.
+ */
+ public static Command buildSequencePaneBasedSelectionWizardCommandFromTool(PaneBasedSelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement,
+ EventEnd endBefore, Point location) {
+ CommandBuilder builder = new SequencePaneBasedSelectionWizardCommandBuilder(tool, dContainer, selectedElement, endBefore, location);
+ Session session = SessionManager.INSTANCE.getSession(dContainer.getTarget());
+ return getCommand(builder, session);
+ }
+
+ /**
+ * Builds the command which will execute the user-specified operations with
+ * a selection tool.
+ *
+ * @param tool
+ * the selection tool.
+ * @param dContainer
+ * the clicked diagram element.
+ * @param selectedElement
+ * the selected elements
+ * @param endBefore
+ * the event end graphically preceding the position
+ * @param location
+ * the clicked location.
+ * @return a command to execute the tool.
+ */
+ public static Command buildSequenceSelectionWizardCommandFromTool(SelectionWizardDescription tool, DSemanticDecorator dContainer, Collection<EObject> selectedElement, EventEnd endBefore,
+ Point location) {
+ CommandBuilder builder = new SequenceSelectionWizardCommandBuilder(tool, dContainer, selectedElement, endBefore, location);
+ Session session = SessionManager.INSTANCE.getSession(dContainer.getTarget());
+ return getCommand(builder, session);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/BendpointsHelper.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/BendpointsHelper.java
new file mode 100644
index 0000000000..5a40fff33e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/BendpointsHelper.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Helper to compare two lists of GMF RelativeBenpoint to help avoid re-setting
+ * the same values (which can trigger unwanted notifications).
+ *
+ * @author pcdavid
+ */
+public final class BendpointsHelper {
+ private BendpointsHelper() {
+ // Prevents instantiations.
+ }
+
+ /**
+ * Checks whether two objects are lists of GMF Bendpoints which are
+ * equivalent (i.e. the same number of points with the same coordinates in
+ * the same order).
+ *
+ * @param oldValue
+ * the first (old) value.
+ * @param newValue
+ * the second (new) value.
+ * @return <code>true</code> if the two given values are equivalent lists of
+ * GMF Bendpoints.
+ */
+ public static boolean areSameBendpoints(Object oldValue, Object newValue) {
+ boolean isTouch = false;
+ if (oldValue instanceof Collection<?> && newValue instanceof Collection<?>) {
+ List<RelativeBendpoint> newPoints = Lists.newArrayList(Iterables.filter((Collection<?>) newValue, RelativeBendpoint.class));
+ List<RelativeBendpoint> oldPoints = Lists.newArrayList(Iterables.filter((Collection<?>) oldValue, RelativeBendpoint.class));
+ if (newPoints.size() == oldPoints.size()) {
+ isTouch = true;
+ for (int i = 0; i < newPoints.size(); i++) {
+ RelativeBendpoint newPoint = newPoints.get(i);
+ RelativeBendpoint oldPoint = oldPoints.get(i);
+
+ boolean sourceTouch = newPoint.getSourceX() == oldPoint.getSourceX() && newPoint.getSourceY() == oldPoint.getSourceY();
+ boolean targetTouch = newPoint.getTargetX() == oldPoint.getTargetX() && newPoint.getTargetY() == oldPoint.getTargetY();
+
+ if (!(sourceTouch && targetTouch)) {
+ isTouch = false;
+ break;
+ }
+ }
+ }
+ }
+ return isTouch;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/EventFinder.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/EventFinder.java
new file mode 100644
index 0000000000..768b29b8ed
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/EventFinder.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+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.Maps;
+
+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.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.util.Range;
+
+/**
+ * Helper to locate sequence events inside a given context event.
+ *
+ * @author pcdavid
+ */
+public class EventFinder {
+ private final ISequenceEvent context;
+
+ private final Lifeline lifeline;
+
+ private Range expansionZone;
+
+ private Predicate<ISequenceEvent> eventsToIgnore;
+
+ private boolean reconnect;
+
+ private boolean reparent;
+
+ private Function<ISequenceEvent, Range> verticalRangeFunction = new Function<ISequenceEvent, Range>() {
+ public Range apply(ISequenceEvent from) {
+ return from.getVerticalRange();
+ }
+ };
+
+ private Map<AbstractNodeEvent, ISequenceEvent> reparented = Maps.newHashMap();
+
+ /**
+ * Constructor.
+ *
+ * @param context
+ * the event in which to look for. Only sub-events of the context
+ * are considered in the search.
+ */
+ public EventFinder(Lifeline context) {
+ this.context = context;
+ this.lifeline = context;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param context
+ * the event in which to look for. Only sub-events of the context
+ * are considered in the search.
+ */
+ public EventFinder(AbstractNodeEvent context) {
+ this.context = context;
+ Preconditions.checkArgument(context.getLifeline().some());
+ this.lifeline = context.getLifeline().get();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param context
+ * the event in which to look for. Only sub-events of the context
+ * are considered in the search.
+ *
+ * @param lifeline
+ * the lifeline on which to look for an event.
+ */
+ public EventFinder(ISequenceEvent context, Lifeline lifeline) {
+ this.context = context;
+ this.lifeline = lifeline;
+ }
+
+ /**
+ * Allow to use another way to compute the range of the context (iG range
+ * after move?..).
+ *
+ * @param rangeFunction
+ * the range function to use to compute the context range.
+ */
+ public void setVerticalRangefunction(Function<ISequenceEvent, Range> rangeFunction) {
+ if (verticalRangeFunction != null) {
+ this.verticalRangeFunction = rangeFunction;
+ }
+ }
+
+ public void setReconnection(boolean mode) {
+ this.reconnect = mode;
+ }
+
+ public boolean isReconnection() {
+ return reconnect;
+ }
+
+ public void setReparent(boolean mode) {
+ this.reparent = mode;
+ }
+
+ public boolean isReparent() {
+ return reparent;
+ }
+
+ public void setExpansionZone(Range expansionZone) {
+ this.expansionZone = expansionZone;
+ }
+
+ public void setEventsToIgnore(Predicate<ISequenceEvent> eventsToIgnore) {
+ this.eventsToIgnore = eventsToIgnore;
+ }
+
+ /**
+ * Returns the deepest event in the hierarchy of sub-event starting from
+ * this finder's context which includes completely the specified range.
+ *
+ * @param range
+ * the range to look for.
+ * @return the deepest event, starting from this finder's context, which
+ * includes the specified range, or <code>null</code>.
+ */
+ public ISequenceEvent findMostSpecificEvent(Range range) {
+ if (context instanceof Message) {
+ return null;
+ }
+ ISequenceEvent result = null;
+ if (contextIncludesRange(range)) {
+ if (context != null && !shouldIgnore().apply(context)) {
+ boolean okForReconnection = !isReconnection() || !Message.NO_RECONNECTABLE_EVENTS.apply(context);
+ boolean okForReparent = !isReparent() || !AbstractNodeEvent.NO_REPARENTABLE_EVENTS.apply(context);
+ if (okForReconnection && okForReparent) {
+ result = context;
+ }
+ }
+ }
+ if (contextIncludesRange(range) || isReparent()) {
+ Predicate<ISequenceEvent> sameLifeline = new SameLifelinePredicate(lifeline);
+ List<ISequenceEvent> eventsToInspect = Lists.newArrayList();
+ if ((reconnect || reparent) && (context instanceof AbstractNodeEvent || context instanceof Lifeline)) {
+ for (View view : Iterables.filter(context.getNotationView().getChildren(), View.class)) {
+ Option<ISequenceEvent> ise = ISequenceElementAccessor.getISequenceEvent(view);
+ if (ise != null && ise.some() && !reparented.containsKey(ise.get())) {
+ eventsToInspect.add(ise.get());
+ }
+ }
+
+ // handle reparented events
+ // look for new child
+ for (Entry<AbstractNodeEvent, ISequenceEvent> entry : reparented.entrySet()) {
+ if (entry.getValue() == context) {
+ eventsToInspect.add(entry.getKey());
+ }
+ }
+ } else {
+ eventsToInspect.addAll(context.getSubEvents());
+ }
+ for (ISequenceEvent child : Iterables.filter(eventsToInspect, Predicates.and(sameLifeline, Predicates.not(shouldIgnore())))) {
+ EventFinder childFinder = new EventFinder(child, lifeline);
+ childFinder.setReconnection(isReconnection());
+ childFinder.setReparent(isReparent());
+ childFinder.setEventsToIgnore(eventsToIgnore);
+ childFinder.setExpansionZone(expansionZone);
+ childFinder.setVerticalRangefunction(verticalRangeFunction);
+ childFinder.setReparented(reparented);
+ ISequenceEvent moreSpecific = childFinder.findMostSpecificEvent(range);
+ if (moreSpecific != null) {
+ result = moreSpecific;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Tests whether this finder's context element includes the specified range,
+ * considering the optional expansion step.
+ */
+ private boolean contextIncludesRange(Range range) {
+ Range currentContextRange = verticalRangeFunction.apply(context);
+ return getRangeAfterExpansion(currentContextRange).includes(range);
+ }
+
+ /**
+ * Returns a predicate which tests whether an element should be ignored in
+ * the search for descendants.
+ */
+ private Predicate<ISequenceEvent> shouldIgnore() {
+ if (eventsToIgnore == null) {
+ return Predicates.alwaysFalse();
+ } else {
+ return eventsToIgnore;
+ }
+ }
+
+ private Range getRangeAfterExpansion(Range range) {
+ if (expansionZone != null && range.includesAtLeastOneBound(expansionZone)) {
+ return range.union(expansionZone);
+ } else {
+ return range;
+ }
+ }
+
+ /**
+ * Handle already reparented event.
+ *
+ * @param newParents
+ * key is the reparented exec, value is the new parent.
+ */
+ public void setReparented(Map<AbstractNodeEvent, ISequenceEvent> newParents) {
+ this.reparented.putAll(newParents);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceElementSwitch.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceElementSwitch.java
new file mode 100644
index 0000000000..205d955741
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceElementSwitch.java
@@ -0,0 +1,579 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.business.api.query.DiagramElementMappingQuery;
+import org.eclipse.sirius.description.DiagramElementMapping;
+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.EndOfLife;
+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.InstanceRole;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.InteractionUse;
+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.description.DescriptionPackage;
+
+/**
+ * <!-- begin-user-doc --> The <b>Switch</b> for the sequence elements's
+ * inheritance hierarchy. It supports the call
+ * {@link #doSwitch(ISequenceElement) doSwitch(ise)} to invoke the
+ * <code>caseXXX</code> method for each class of the model, starting with the
+ * actual class of the object and proceeding up the inheritance hierarchy until
+ * a non-null result is returned, which is the result of the switch. <!--
+ * end-user-doc -->
+ *
+ *
+ * @param <T>
+ * the return type.
+ *
+ * @author mporhel
+ */
+public class ISequenceElementSwitch<T> {
+
+ /**
+ * Creates an instance of the switch.
+ */
+ public ISequenceElementSwitch() {
+
+ }
+
+ /**
+ * Calls <code>caseXXX</code> for each class of the model until one returns
+ * a non null result; it yields that result. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @param element
+ * the element on which to do the switch.
+ * @return the first non-null result returned by a <code>caseXXX</code>
+ * call.
+ */
+ public T doSwitch(ISequenceElement element) {
+ DDiagramElement dde = null;
+ if (element.getNotationView().getElement() instanceof DDiagramElement) {
+ dde = (DDiagramElement) element.getNotationView().getElement();
+ }
+ if (dde != null && dde.getDiagramElementMapping() != null) {
+ DiagramElementMapping mappingToCheck = new DiagramElementMappingQuery(dde.getDiagramElementMapping()).getRootMapping();
+ return doSwitch(mappingToCheck, element);
+ }
+ return null;
+ }
+
+ /**
+ * Calls <code>caseXXX</code> for each class of the model until one returns
+ * a non null result; it yields that result. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @param mapping
+ * the considered mapping for the swith (mapping of the element).
+ * @param element
+ * the element on which to do the switch.
+ * @return the first non-null result returned by a <code>caseXXX</code>
+ * call.
+ */
+ protected T doSwitch(DiagramElementMapping mapping, ISequenceElement element) {
+ if (mapping != null && mapping.eClass().getEPackage() == DescriptionPackage.eINSTANCE) {
+ return doSwitch(mapping.eClass().getClassifierID(), element);
+ } else {
+ return defaultCase(element);
+ }
+ }
+
+ /**
+ * Calls <code>caseXXX</code> for each class of the model until one returns
+ * a non null result; it yields that result. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @return the first non-null result returned by a <code>caseXXX</code>
+ * call.
+ * @generated
+ */
+ // CHECKSTYLE:OFF
+ protected T doSwitch(int classifierID, ISequenceElement element) {
+ switch (classifierID) {
+ case DescriptionPackage.SEQUENCE_DIAGRAM_DESCRIPTION: {
+ SequenceDiagram diag = (SequenceDiagram) element;
+ T result = caseSequenceDiagram(diag);
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.INSTANCE_ROLE_MAPPING: {
+ InstanceRole instanceRole = (InstanceRole) element;
+ T result = caseInstanceRole(instanceRole);
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.EVENT_MAPPING: {
+ ISequenceEvent event = (ISequenceEvent) element;
+ T result = caseEvent(event);
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.DELIMITED_EVENT_MAPPING: {
+ ISequenceEvent delimitedEvent = (ISequenceEvent) element;
+ T result = caseDelimitedEvent(delimitedEvent);
+ if (result == null) {
+ result = caseEvent(delimitedEvent);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.EXECUTION_MAPPING: {
+ Execution execution = (Execution) element;
+ T result = caseExecution(execution);
+ if (result == null) {
+ result = caseDelimitedEvent(execution);
+ }
+ if (result == null) {
+ result = caseEvent(execution);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.STATE_MAPPING: {
+ State state = (State) element;
+ T result = caseState(state);
+ if (result == null) {
+ result = caseDelimitedEvent(state);
+ }
+ if (result == null) {
+ result = caseEvent(state);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.END_OF_LIFE_MAPPING: {
+ EndOfLife endOfLife = (EndOfLife) element;
+ T result = caseEndOfLife(endOfLife);
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+
+ case DescriptionPackage.BASIC_MESSAGE_MAPPING: {
+ Message basicMessage = (Message) element;
+ T result = caseBasicMessage(basicMessage);
+ if (result == null) {
+ result = caseMessage(basicMessage);
+ }
+ return result;
+ }
+ case DescriptionPackage.RETURN_MESSAGE_MAPPING: {
+ Message returnMessage = (Message) element;
+ T result = caseReturnMessage(returnMessage);
+ if (result == null) {
+ result = caseMessage(returnMessage);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.CREATION_MESSAGE_MAPPING: {
+ Message creationMessage = (Message) element;
+ T result = caseCreationMessage(creationMessage);
+ if (result == null) {
+ result = caseMessage(creationMessage);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.DESTRUCTION_MESSAGE_MAPPING: {
+ Message destructionMessage = (Message) element;
+ T result = caseDestructionMessage(destructionMessage);
+ if (result == null) {
+ result = caseMessage(destructionMessage);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.FRAME_MAPPING: {
+ AbstractFrame frame = (AbstractFrame) element;
+ T result = caseFrame(frame);
+ if (result == null) {
+ result = caseDelimitedEvent(frame);
+ }
+ if (result == null) {
+ result = caseEvent(frame);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.INTERACTION_USE_MAPPING: {
+ InteractionUse interactionUse = (InteractionUse) element;
+ T result = caseInteractionUse(interactionUse);
+ if (result == null) {
+ result = caseFrame(interactionUse);
+ }
+ if (result == null) {
+ result = caseDelimitedEvent(interactionUse);
+ }
+ if (result == null) {
+ result = caseEvent(interactionUse);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.COMBINED_FRAGMENT_MAPPING: {
+ CombinedFragment combinedFragment = (CombinedFragment) element;
+ T result = caseCombinedFragment(combinedFragment);
+ if (result == null) {
+ result = caseFrame(combinedFragment);
+ }
+ if (result == null) {
+ result = caseDelimitedEvent(combinedFragment);
+ }
+ if (result == null) {
+ result = caseEvent(combinedFragment);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ case DescriptionPackage.OPERAND_MAPPING: {
+ Operand operand = (Operand) element;
+ T result = caseOperand(operand);
+ if (result == null) {
+ result = caseDelimitedEvent(operand);
+ }
+ if (result == null) {
+ result = caseEvent(operand);
+ }
+ if (result == null) {
+ result = defaultCase(element);
+ }
+ return result;
+ }
+ default:
+ return defaultCase(element);
+ }
+ }
+
+ // CHECKSTYLE:ON
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Sequence Diagram Description</em>'. <!-- begin-user-doc --> This
+ * implementation returns null; returning a non-null result will terminate
+ * the switch. <!-- end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Sequence Diagram</em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseSequenceDiagram(SequenceDiagram object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Instance Role </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Instance Role </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseInstanceRole(InstanceRole object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Event </em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Event </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseEvent(ISequenceEvent object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Delimited Event </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Delimited Event </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseDelimitedEvent(ISequenceEvent object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Execution </em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Execution </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseExecution(Execution object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>State </em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>State </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseState(State object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>End Of Life </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>End Of Life </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseEndOfLife(EndOfLife object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Message </em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Message </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseMessage(Message object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Basic Message </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Basic Message </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseBasicMessage(Message object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Return Message </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Return Message </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseReturnMessage(Message object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Creation Message </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Creation Message </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseCreationMessage(Message object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Destruction Message </em>'. <!-- begin-user-doc --> This
+ * implementation returns null; returning a non-null result will terminate
+ * the switch. <!-- end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Destruction Message </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseDestructionMessage(Message object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Frame </em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Frame </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseFrame(AbstractFrame object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Interaction Use </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Interaction Use </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseInteractionUse(InteractionUse object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Combined Fragment </em>'. <!-- begin-user-doc --> This implementation
+ * returns null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Combined Fragment </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseCombinedFragment(CombinedFragment object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>Operand </em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch. <!--
+ * end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>Operand </em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseOperand(Operand object) {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '
+ * <em>EObject</em>'. <!-- begin-user-doc --> This implementation returns
+ * null; returning a non-null result will terminate the switch, but this is
+ * the last case anyway. <!-- end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '
+ * <em>EObject</em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject)
+ * @generated
+ */
+ public T defaultCase(ISequenceElement object) {
+ return null;
+ }
+
+} // DescriptionSwitch
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceEventsTreeIterator.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceEventsTreeIterator.java
new file mode 100644
index 0000000000..872fffc492
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ISequenceEventsTreeIterator.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.common.util.AbstractTreeIterator;
+
+import com.google.common.collect.Iterators;
+
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.ISequenceEvent;
+
+/**
+ * A tree iterator to iterate on hierarchies of ISequenceEvent.
+ *
+ * @author pcdavid
+ */
+public class ISequenceEventsTreeIterator extends AbstractTreeIterator<ISequenceEvent> {
+ /**
+ * Generated serial version UID.
+ */
+ private static final long serialVersionUID = 3234398995856675133L;
+
+ /**
+ * Creates a new tree iterator on the specified event and all its descendant
+ * events.
+ *
+ * @param root
+ * the root event of the iteration.
+ */
+ public ISequenceEventsTreeIterator(ISequenceEvent root) {
+ super(root);
+ }
+
+ /**
+ * Creates a new tree iterator on the descendants of the specified event.
+ *
+ * @param root
+ * the root event of the iteration.
+ * @param includeRoot
+ * if <code>true</code>, the iterator includes the root element.
+ */
+ public ISequenceEventsTreeIterator(ISequenceEvent root, boolean includeRoot) {
+ super(root, includeRoot);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Iterator<? extends ISequenceEvent> getChildren(Object object) {
+ if (object instanceof ISequenceEvent) {
+ Iterable<ISequenceEvent> children = ((ISequenceEvent) object).getSubEvents();
+ return children.iterator();
+ } else {
+ return Iterators.emptyIterator();
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ParentOperandFinder.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ParentOperandFinder.java
new file mode 100644
index 0000000000..cbcdda5776
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/ParentOperandFinder.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+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 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.Execution;
+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.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;
+
+/**
+ * .
+ *
+ * @author mporhel
+ *
+ */
+public final class ParentOperandFinder {
+
+ private static Collection<Class<?>> types = new ArrayList<Class<?>>();
+ {
+ types.add(Lifeline.class);
+ types.add(AbstractNodeEvent.class);
+ types.add(Execution.class);
+ types.add(State.class);
+ types.add(InteractionUse.class);
+ types.add(CombinedFragment.class);
+ types.add(Message.class);
+ }
+
+ private Function<ISequenceEvent, Range> rangeFunction = ISequenceEvent.VERTICAL_RANGE;
+
+ private ISequenceEvent event;
+
+ /**
+ * Default constructor.
+ *
+ * @param event
+ * a supported {@link ISequenceEvent} : {@linkLifeline},
+ * {@link AbstractNodeEvent}, {@link Operand}.
+ */
+ public ParentOperandFinder(ISequenceEvent event) {
+ Preconditions.checkArgument(types.contains(event.getClass()));
+ Preconditions.checkNotNull(event);
+ this.event = event;
+ }
+
+ /**
+ * Default constructor.
+ *
+ * @param event
+ * a supported {@link ISequenceEvent} : {@linkLifeline},
+ * {@link AbstractNodeEvent}, {@link Operand}.
+ * @param rangeFunction
+ * function to compute expected range.
+ */
+ public ParentOperandFinder(ISequenceEvent event, Function<ISequenceEvent, Range> rangeFunction) {
+ this(event);
+ Preconditions.checkNotNull(rangeFunction);
+ this.rangeFunction = rangeFunction;
+ }
+
+ /**
+ * Find the parent operand if exists.
+ *
+ * @return the potential parent operand.
+ */
+ public Option<Operand> getParentOperand() {
+ Range verticalRange = rangeFunction.apply(event);
+ return getParentOperand(verticalRange);
+ }
+
+ /**
+ * Finds the deepest Operand container convering the range if existing.
+ *
+ * @param verticalRange
+ * the range where to look for the deepest operand
+ * @return the deepest Operand convering this lifeline at this range
+ * @see ISequenceEvent#getParentOperand()
+ */
+ public Option<Operand> getParentOperand(final Range verticalRange) {
+ SequenceDiagram diagram = event.getDiagram();
+ Set<Operand> allOperands = diagram.getAllOperands();
+
+ Predicate<Operand> coveredLifeline = new Predicate<Operand>() {
+ // Filter the operands that cover the execution parent lifeline
+ public boolean apply(Operand input) {
+ Collection<Lifeline> computeCoveredLifelines = input.computeCoveredLifelines();
+ return computeCoveredLifelines != null && computeCoveredLifelines.contains(event.getLifeline().get());
+ }
+ };
+
+ Predicate<Operand> includingExecutionRange = new Predicate<Operand>() {
+ // Filter the operands having a range that contains the execution
+ // range (we consider the insertion point : lowerbound of range)
+ public boolean apply(Operand input) {
+ return rangeFunction.apply(input).includes(new Range(verticalRange.getLowerBound(), verticalRange.getLowerBound()));
+ // return rangeFunction.apply(input).includes(verticalRange);
+ }
+ };
+
+ Operand deepestCoveringOperand = null;
+
+ for (Operand operand : Iterables.filter(allOperands, Predicates.and(coveredLifeline, includingExecutionRange))) {
+ // Find the deepest operand among the filtered ones
+ if (deepestCoveringOperand == null || rangeFunction.apply(deepestCoveringOperand).includes(rangeFunction.apply(operand))) {
+ deepestCoveringOperand = operand;
+ }
+ }
+ if (deepestCoveringOperand != null) {
+ return Options.newSome(deepestCoveringOperand);
+ } else {
+ return Options.newNone();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/RangeSetter.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/RangeSetter.java
new file mode 100644
index 0000000000..2a87b40a77
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/RangeSetter.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Edge;
+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.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.Size;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+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.CombinedFragment;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.EndOfLife;
+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.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.Operand;
+import org.eclipse.sirius.diagram.sequence.business.internal.elements.State;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceMessageViewQuery;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.SequenceNodeQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * .
+ *
+ * @author mporhel
+ *
+ */
+public final class RangeSetter {
+
+ /**
+ * Avoid instanticiation.
+ */
+ private RangeSetter() {
+ // Do nothing.
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for lifelines and
+ * executions. Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the (root) execution edit part.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(AbstractNodeEvent self, Range range) {
+ Range oldRange = self.getVerticalRange();
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = range.width();
+
+ RangeSetter.setVerticalRange(self.getNotationNode(), deltaY, size);
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for states.
+ * Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the state edit part.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(State self, Range range) {
+ Range oldRange = self.getVerticalRange();
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = range.width();
+
+ RangeSetter.setVerticalRange(self.getNotationNode(), deltaY, size);
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for interaction
+ * uses. Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the InteractionUse.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(InteractionUse self, Range range) {
+ Range oldRange = self.getVerticalRange();
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = range.width();
+
+ RangeSetter.setVerticalRange(self.getNotationNode(), deltaY, size);
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for combined
+ * fragments. Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the CombinedFragment.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(CombinedFragment self, Range range) {
+ Range oldRange = self.getVerticalRange();
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = range.width();
+
+ RangeSetter.setVerticalRange(self.getNotationNode(), deltaY, size);
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for combined
+ * fragments. Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the CombinedFragment.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(Operand self, Range range) {
+ Range oldRange = self.getVerticalRange();
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = range.width();
+
+ RangeSetter.setVerticalRange(self.getNotationNode(), deltaY, size);
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for lifelines and
+ * executions. Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the (root) execution edit part.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(Lifeline self, Range range) {
+ InstanceRole instanceRole = self.getInstanceRole();
+ Rectangle irepBounds = instanceRole.getBounds();
+ Range irRange = new Range(range.getLowerBound() - irepBounds.height, range.getUpperBound());
+ RangeSetter.setVerticalRange(instanceRole, irRange);
+
+ Range oldRange = self.getVerticalRange();
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = range.width();
+ RangeSetter.setVerticalRange(self.getNotationNode(), deltaY, size);
+
+ Option<EndOfLife> eol = self.getEndOfLife();
+ if (eol.some()) {
+ EndOfLife endOfLife = eol.get();
+ Rectangle eolBounds = endOfLife.getBounds();
+ Range eolRange = new Range(range.getUpperBound(), range.getUpperBound() + eolBounds.height);
+ RangeSetter.setVerticalRange(endOfLife, eolRange);
+ }
+ }
+
+ /**
+ * .
+ *
+ * @param self
+ * .
+ * @param range
+ * .
+ */
+ private static void setVerticalRange(InstanceRole self, Range range) {
+ Node node = self.getNotationNode();
+ Range oldRange = new SequenceNodeQuery(node).getVerticalRange();
+
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = oldRange.width();
+
+ RangeSetter.setVerticalRange(node, deltaY, size);
+ }
+
+ /**
+ * .
+ *
+ * @param self
+ * .
+ * @param range
+ * .
+ */
+ private static void setVerticalRange(EndOfLife self, Range range) {
+ Node node = self.getNotationNode();
+ Range oldRange = new SequenceNodeQuery(node).getVerticalRange();
+
+ int deltaY = range.getLowerBound() - oldRange.getLowerBound();
+ int size = oldRange.width();
+
+ RangeSetter.setVerticalRange(node, deltaY, size);
+ }
+
+ /**
+ * .
+ *
+ * @param node
+ * .
+ * @param deltaY
+ * .
+ * @param size
+ * .
+ */
+ private static void setVerticalRange(Node node, int deltaY, int size) {
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ int realDeltaY = deltaY;
+ // if (realDeltaY > 0) {
+ // realDeltaY -= IBorderItemOffsets.DEFAULT_OFFSET.height;
+ // }else if(realDeltaY<0){
+ // realDeltaY += IBorderItemOffsets.DEFAULT_OFFSET.height;
+ // }
+ if (layoutConstraint instanceof Location && realDeltaY != 0) {
+ Location location = (Location) layoutConstraint;
+ location.setY(location.getY() + realDeltaY);
+ }
+ if (layoutConstraint instanceof Size) {
+ Size s = (Size) layoutConstraint;
+ if (s.getHeight() != size) {
+ s.setHeight(size);
+ }
+ }
+ }
+
+ /**
+ * Common implementation of
+ * {@link ISequenceEventEditPart#setVerticalRange(Range)} for lifelines and
+ * executions. Assumes the {@link ISequenceEventEditPart} is a Node.
+ *
+ * @param self
+ * the (root) execution edit part.
+ * @param range
+ * the vertical range of the given sequence event.
+ */
+ public static void setVerticalRange(Message self, Range range) {
+ RangeSetter.handlePotentialLostEnd(self.getSourceElement(), range);
+ RangeSetter.handlePotentialLostEnd(self.getTargetElement(), range);
+
+ Edge edge = self.getNotationEdge();
+ SequenceMessageViewQuery query = new SequenceMessageViewQuery(edge);
+
+ int firstPointVerticalPosition = query.getFirstPointVerticalPosition(true);
+ int lastPointVerticalPosition = query.getLastPointVerticalPosition(true);
+
+ int firstPointVerticalPositionFromTarget = query.getFirstPointVerticalPosition(false);
+ int lastPointVerticalPositionFromTarget = query.getLastPointVerticalPosition(false);
+
+ int deltaFirstPointY = range.getLowerBound() - firstPointVerticalPosition;
+ int deltaFirstPointYFromTarget = range.getLowerBound() - firstPointVerticalPositionFromTarget;
+
+ int deltaLastPointY = range.getUpperBound() - lastPointVerticalPosition;
+ int deltaLastPointYFromTarget = range.getUpperBound() - lastPointVerticalPositionFromTarget;
+
+ RangeSetter.updateBendpoints(edge, firstPointVerticalPosition, lastPointVerticalPosition, deltaFirstPointY, deltaFirstPointYFromTarget, deltaLastPointY, deltaLastPointYFromTarget);
+ }
+
+ private static void handlePotentialLostEnd(ISequenceNode end, Range range) {
+ if (end instanceof LostMessageEnd) {
+ Node node = end.getNotationNode();
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ Bounds bounds = (Bounds) layoutConstraint;
+ int middleValue = bounds.getY() + bounds.getHeight() / 2;
+ RangeSetter.setVerticalRange(node, range.middleValue() - middleValue, bounds.getHeight());
+ }
+ }
+ }
+
+ private static void updateBendpoints(Edge edge, int firstPointVerticalPosition, int lastPointVerticalPosition, int deltaFirstPointY, int deltaFirstPointYFromTarget, int deltaLastPointY,
+ int deltaLastPointYFromTarget) {
+ List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>();
+ RelativeBendpoints bendpoints = (RelativeBendpoints) edge.getBendpoints();
+
+ Iterable<RelativeBendpoint> relPoints = Iterables.filter(bendpoints.getPoints(), RelativeBendpoint.class);
+
+ for (int i = 0; i < Iterables.size(relPoints) / 2; i++) {
+ RelativeBendpoint p = Iterables.get(relPoints, i);
+ RangeSetter.addBendpoint(newBendpoints, p, deltaFirstPointY, deltaFirstPointYFromTarget);
+ }
+
+ for (int i = Iterables.size(relPoints) / 2; i < Iterables.size(relPoints); i++) {
+ RelativeBendpoint p = Iterables.get(relPoints, i);
+ RangeSetter.addBendpoint(newBendpoints, p, deltaLastPointY, deltaLastPointYFromTarget);
+ }
+
+ if (!BendpointsHelper.areSameBendpoints(bendpoints.getPoints(), newBendpoints)) {
+ bendpoints.setPoints(newBendpoints);
+ }
+ }
+
+ private static void addBendpoint(List<RelativeBendpoint> newBendpoints, RelativeBendpoint p, double deltaSourceY, double deltaTargetY) {
+ newBendpoints.add(new RelativeBendpoint(p.getSourceX(), (int) (p.getSourceY() + deltaSourceY), p.getTargetX(), (int) (p.getTargetY() + deltaTargetY)));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SameLifelinePredicate.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SameLifelinePredicate.java
new file mode 100644
index 0000000000..321701389d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SameLifelinePredicate.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.business.internal.util;
+
+import java.util.Collection;
+
+import com.google.common.base.Predicate;
+
+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.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.Operand;
+
+/**
+ * Predicate used to filter {@link ISequenceEvent} owned by one specified
+ * {@link Lifeline}.
+ *
+ * @author edugueperoux
+ */
+public class SameLifelinePredicate implements Predicate<ISequenceEvent> {
+
+ private Lifeline owner;
+
+ /**
+ * Default constructor.
+ *
+ * @param owner
+ * the {@link Lifeline} owner
+ */
+ public SameLifelinePredicate(Lifeline owner) {
+ assert owner != null;
+ this.owner = owner;
+ }
+
+ /**
+ * Overridden to tells if the specified {@link ISequenceEvent} is owned by
+ * the current {@link Lifeline}.
+ *
+ * {@inheritDoc}
+ */
+ public boolean apply(ISequenceEvent input) {
+ boolean result = false;
+ Option<Lifeline> inputLifeline = input.getLifeline();
+ if (inputLifeline.some()) {
+ result = inputLifeline.get().equals(owner);
+ } else if (input instanceof Message) {
+ Message message = (Message) input;
+ ISequenceNode sourceElt = message.getSourceElement();
+ ISequenceNode targetElt = message.getSourceElement();
+ Option<Lifeline> sourceLifeline = sourceElt.getLifeline();
+ Option<Lifeline> targetLifeline = targetElt.getLifeline();
+ result = sourceLifeline.some() && sourceLifeline.get().equals(owner) || targetLifeline.some() && targetLifeline.get().equals(owner);
+ } else if (input instanceof Operand) {
+ result = true;
+ } else if (input instanceof AbstractFrame) {
+ AbstractFrame frame = (AbstractFrame) input;
+ Collection<Lifeline> coverage = frame.computeCoveredLifelines();
+ result = coverage.contains(owner);
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SubEventsHelper.java b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SubEventsHelper.java
new file mode 100644
index 0000000000..3336a8ba04
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.sequence/src/org/eclipse/sirius/diagram/sequence/business/internal/util/SubEventsHelper.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * 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.business.internal.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+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.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.CombinedFragment;
+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.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.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.ordering.EventEndHelper;
+import org.eclipse.sirius.diagram.sequence.business.internal.query.ISequenceEventQuery;
+import org.eclipse.sirius.diagram.sequence.util.Range;
+
+/**
+ * .
+ *
+ * @author mporhel
+ *
+ */
+public final class SubEventsHelper {
+
+ private static Collection<Class<?>> types = Lists.newArrayList();
+ {
+ types.add(Execution.class);
+ types.add(Lifeline.class);
+ types.add(Operand.class);
+ }
+
+ private ISequenceEvent parentEvent;
+
+ private Range parentRange;
+
+ private final Multimap<ISequenceEvent, Lifeline> coverage = HashMultimap.create();
+
+ /**
+ * Default constructor.
+ *
+ * @param event
+ * a supported {@link ISequenceEvent} : {@linkLifeline},
+ * {@link AbstractNodeEvent}, {@link Operand}.
+ */
+ public SubEventsHelper(ISequenceEvent event) {
+ Preconditions.checkArgument(types.contains(event.getClass()));
+ Preconditions.checkNotNull(event);
+ this.parentEvent = event;
+ this.parentRange = event.getVerticalRange();
+ }
+
+ /**
+ * Common implementation of {@link ISequenceEvent#getSubEvents()}.
+ *
+ * @return the sub-events of the (root) execution, ordered by their starting
+ * position (graphically) from top to bottom.
+ */
+ public List<ISequenceEvent> getSubEvents() {
+ List<ISequenceEvent> result = getValidSubEvents();
+ Collections.sort(result, Range.lowerBoundOrdering().onResultOf(ISequenceEvent.VERTICAL_RANGE));
+ return result;
+ }
+
+ /**
+ * Compute childs of Execution/Operand/Lifeline.
+ *
+ * @return the sub events.
+ */
+ private List<ISequenceEvent> getValidSubEvents() {
+ List<ISequenceEvent> childrenEvents = Lists.newArrayList();
+
+ Set<ISequenceEvent> localParents = Sets.newHashSet();
+ Set<Lifeline> coveredLifelines = Sets.newHashSet();
+ if (parentEvent instanceof AbstractNodeEvent || parentEvent instanceof Lifeline) {
+ localParents.add(parentEvent);
+ coveredLifelines.add(parentEvent.getLifeline().get());
+ } else if (parentEvent instanceof Operand) {
+ Operand op = (Operand) parentEvent;
+ CombinedFragment parentCombinedFragment = op.getCombinedFragment();
+ coveredLifelines.addAll(getCoverage(parentCombinedFragment));
+ localParents.addAll(getCarryingParents(parentCombinedFragment, coveredLifelines));
+ }
+
+ Set<ISequenceEvent> hierarchicalChildren = getNotationDirectChildrenInParentRange(localParents);
+ Set<ISequenceEvent> frameChildren = getFrameChildrenInParentRange(coveredLifelines);
+
+ childrenEvents.addAll(getTopLevelEvents(hierarchicalChildren, frameChildren, coveredLifelines));
+ childrenEvents.addAll(getTopLevelEvents(frameChildren, childrenEvents, coveredLifelines));
+
+ return childrenEvents;
+ }
+
+ private Collection<Lifeline> getCoverage(ISequenceEvent ise) {
+ if (coverage.containsKey(ise)) {
+ return coverage.get(ise);
+ }
+
+ Option<Lifeline> lifeline = ise.getLifeline();
+ Collection<Lifeline> coveredLifelines = Lists.newArrayList();
+ if (lifeline.some()) {
+ coveredLifelines.add(lifeline.get());
+ } else if (ise instanceof Operand) {
+ coveredLifelines.addAll(getCoverage(((Operand) ise).getCombinedFragment()));
+ } else if (ise instanceof AbstractFrame) {
+ coveredLifelines.addAll(((AbstractFrame) ise).computeCoveredLifelines());
+ } else if (ise instanceof Message) {
+ Message msg = (Message) ise;
+ Option<Lifeline> sourceLifeline = msg.getSourceLifeline();
+ if (sourceLifeline.some()) {
+ coveredLifelines.add(sourceLifeline.get());
+ }
+ Option<Lifeline> targetLifeline = msg.getTargetLifeline();
+ if (targetLifeline.some()) {
+ coveredLifelines.add(targetLifeline.get());
+ }
+ }
+ coverage.putAll(ise, coveredLifelines);
+ return coveredLifelines;
+ }
+
+ private Collection<ISequenceEvent> getCarryingParents(AbstractFrame frame, Set<Lifeline> coveredLifelines) {
+ Set<ISequenceEvent> coveredEvents = Sets.newHashSet();
+ for (Lifeline lifeline : coveredLifelines) {
+ EventFinder localParentFinder = new EventFinder(lifeline);
+ localParentFinder.setReparent(true);
+ localParentFinder.setEventsToIgnore(Predicates.equalTo((ISequenceEvent) frame));
+ ISequenceEvent localParent = localParentFinder.findMostSpecificEvent(frame.getVerticalRange());
+ if (localParent != null) {
+ coveredEvents.add(localParent);
+ }
+ }
+ return coveredEvents;
+ }
+
+ /**
+ * Look for execution and lifeline
+ *
+ * @param localParents
+ * @return
+ */
+ private Set<ISequenceEvent> getNotationDirectChildrenInParentRange(Set<ISequenceEvent> localParents) {
+ Collection<View> childViews = Sets.newLinkedHashSet();
+ Collection<View> parentConnections = Sets.newHashSet();
+ Set<ISequenceEvent> childrenEvents = Sets.newHashSet();
+
+ for (ISequenceEvent ise : localParents) {
+ View notationView = ise.getNotationView();
+ childViews.addAll(Lists.newArrayList(Iterables.filter(notationView.getChildren(), View.class)));
+
+ Collection<View> sourceEdges = Lists.newArrayList(Iterables.filter(notationView.getSourceEdges(), View.class));
+ Collection<View> targetEdges = Lists.newArrayList(Iterables.filter(notationView.getTargetEdges(), View.class));
+
+ childViews.addAll(sourceEdges);
+ childViews.addAll(targetEdges);
+
+ // In some resize cases, edges could appears to be out of their
+ // source/target ranges
+ if (ise == parentEvent) {
+ parentConnections.addAll(sourceEdges);
+ parentConnections.addAll(targetEdges);
+ }
+ }
+
+ for (View view : childViews) {
+ Option<ISequenceEvent> iSequenceEvent = ISequenceElementAccessor.getISequenceEvent(view);
+ if (iSequenceEvent.some()) {
+ ISequenceEvent ise = iSequenceEvent.get();
+ if (parentConnections.contains(view) || parentRange.includes(ise.getVerticalRange())) {
+ childrenEvents.add(iSequenceEvent.get());
+ }
+ }
+ }
+
+ return Sets.newHashSet(EventEndHelper.getIndependantEvents(parentEvent, childrenEvents));
+ }
+
+ private Set<ISequenceEvent> getFrameChildrenInParentRange(Set<Lifeline> coveredLifelines) {
+ Set<ISequenceEvent> childrenEvents = Sets.newHashSet();
+ SequenceDiagram diagram = parentEvent.getDiagram();
+ Set<AbstractFrame> frames = Sets.newHashSet();
+ frames.addAll(diagram.getAllFrames());
+
+ for (AbstractFrame frame : frames) {
+ Range frameRange = frame.getVerticalRange();
+ if (parentRange.includes(frameRange) && validCoverage(frame, coveredLifelines)) {
+ childrenEvents.add(frame);
+ }
+ }
+ return getTopLevelEvents(childrenEvents, childrenEvents, coveredLifelines);
+ }
+
+ private Set<ISequenceEvent> getTopLevelEvents(Set<ISequenceEvent> events, Collection<ISequenceEvent> potentialParents, Set<Lifeline> coveredLifelines) {
+ HashSet<ISequenceEvent> topLevel = Sets.newHashSet();
+ boolean parentFrames = Iterables.size(Iterables.filter(potentialParents, AbstractFrame.class)) != 0;
+
+ for (ISequenceEvent event : events) {
+ final Range verticalRange = event.getVerticalRange();
+ final ISequenceEvent potentialChild = event;
+
+ Predicate<ISequenceEvent> isParentOfCurrent = new Predicate<ISequenceEvent>() {
+ public boolean apply(ISequenceEvent input) {
+ Range inputRange = input.getVerticalRange();
+ boolean isParent = inputRange.includes(verticalRange);
+ return isParent && input != potentialChild;
+ }
+ };
+
+ List<ISequenceEvent> parents = Lists.newArrayList(Iterables.filter(potentialParents, isParentOfCurrent));
+ if (parents.isEmpty()) {
+ topLevel.add(potentialChild);
+ } else if (potentialChild instanceof AbstractFrame && !parentFrames) {
+ Collection<ISequenceEvent> carriers = Lists.newArrayList(getCarryingParents((AbstractFrame) potentialChild, coveredLifelines));
+ Iterables.removeAll(carriers, parents);
+ if (!carriers.isEmpty()) {
+ topLevel.add(potentialChild);
+ }
+ }
+ }
+ return topLevel;
+ }
+
+ private boolean validCoverage(AbstractFrame frame, Set<Lifeline> parentCoveredLifelines) {
+ boolean result = false;
+ Collection<Lifeline> coveredLifelines = getCoverage(frame);
+ if (parentEvent instanceof Operand) {
+ result = parentCoveredLifelines.containsAll(coveredLifelines);
+ } else {
+ result = coveredLifelines.contains(parentEvent.getLifeline().get());
+ }
+
+ return result;
+ }
+
+ /**
+ * Implementation of
+ * {@link ISequenceEvent#canChildOccupy(ISequenceEvent, Range)} .
+ *
+ * @param child
+ * the child.
+ * @param range
+ * the vertical range to test.
+ * @return <code>true</code> if the child can be placed anywhere inside the
+ * specified vertical range (including occupying the whole range).
+ */
+ public boolean canChildOccupy(ISequenceEvent child, Range range) {
+ return canChildOccupy(child, range, null, child == null ? getCoverage(parentEvent) : getCoverage(child));
+ }
+
+ /**
+ * Implementation of
+ * {@link ISequenceEvent#canChildOccupy(ISequenceEvent, Range)} .
+ *
+ * @param child
+ * the child, if child is null it means that it is a insertion
+ * point request from a CreationTool.
+ * @param range
+ * the vertical range to test.
+ * @param eventsToIgnore
+ * the list of events to ignore while compute canChildOccupy.
+ * @param lifelines
+ * lifelines to inspect
+ * @return <code>true</code> if the child can be placed anywhere inside the
+ * specified vertical range (including occupying the whole range).
+ */
+ public boolean canChildOccupy(ISequenceEvent child, final Range range, List<ISequenceEvent> eventsToIgnore, Collection<Lifeline> lifelines) {
+ boolean result = true;
+ if (!parentEvent.getValidSubEventsRange().includes(range)) {
+ result = false;
+ } else {
+ for (ISequenceEvent event : getSequenceEventsToFilter(parentEvent, child, range, lifelines)) {
+ Range eventRange = event.getVerticalRange();
+ if (eventsToIgnore != null && eventsToIgnore.contains(event)) {
+ // do nothing
+ } else if (event instanceof Message) {
+ Message msg = (Message) event;
+ if (!checkOverlapWithSiblingMessage(child, range, msg, eventRange)) {
+ result = false;
+ break;
+ }
+ } else if (eventRange.intersects(range) || !range.validatesBoundsAreDifferent(eventRange)) {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ private boolean checkOverlapWithSiblingMessage(ISequenceEvent child, Range childRange, Message msg, Range msgRange) {
+ boolean result = true;
+ // if event is a SequenceMessageEditPart reconnect it to the
+ // moved child
+ // only if event is a simple message or if full range of its
+ // associated Execution
+ // with the associated messages (call and return) is included in
+ // the future range of the child being dropped
+ if (child instanceof State) {
+ // A state can not have an overlapping message
+ result = !childRange.includesAtLeastOneBound(msgRange);
+ } else if (msg.isReflective()) {
+ if (msgRange.intersects(childRange) && (childRange.getLowerBound() <= msgRange.getLowerBound() || childRange.getUpperBound() >= msgRange.getUpperBound())) {
+ result = false;
+ }
+ } else {
+ ISequenceNode sourceEvent = msg.getSourceElement();
+ ISequenceNode targetEvent = msg.getTargetElement();
+ Execution parentExecEvent = null;
+ if (sourceEvent instanceof Execution) {
+ Execution sourceExec = (Execution) sourceEvent;
+ if (msg.equals(sourceExec.getEndMessage().get())) {
+ parentExecEvent = sourceExec;
+ }
+ }
+
+ if (targetEvent instanceof Execution) {
+ Execution targetExec = (Execution) targetEvent;
+ if (msg.equals(targetExec.getStartMessage().get())) {
+ parentExecEvent = targetExec;
+ }
+ }
+
+ if (parentExecEvent != null) {
+ Range verticalRange = parentExecEvent.getVerticalRange();
+ if (child != null && (!childRange.validatesBoundsAreDifferent(verticalRange) || !childRange.includes(verticalRange) && !verticalRange.includes(childRange))) {
+ result = false;
+ }
+ }
+ }
+ return result;
+ }
+
+ private Iterable<ISequenceEvent> getSequenceEventsToFilter(ISequenceEvent self, ISequenceEvent child, final Range range, final Collection<Lifeline> lifelines) {
+ Set<ISequenceEvent> result = Sets.newHashSet(self.getSubEvents());
+ Predicate<ISequenceEvent> inRangePredicate = new Predicate<ISequenceEvent>() {
+
+ public boolean apply(ISequenceEvent input) {
+ Range inputRange = input.getVerticalRange();
+ return range.includesAtLeastOneBound(inputRange) || new ISequenceEventQuery(input).isReflectiveMessage() && inputRange.includesAtLeastOneBound(range);
+ }
+
+ };
+ Predicate<ISequenceEvent> inCoverage = new Predicate<ISequenceEvent>() {
+
+ public boolean apply(ISequenceEvent input) {
+ Collection<Lifeline> inputCoverage = Lists.newArrayList(getCoverage(input));
+ return Iterables.removeAll(inputCoverage, lifelines);
+ }
+
+ };
+
+ @SuppressWarnings("unchecked")
+ Predicate<ISequenceEvent> predicateFilter = Predicates.and(Predicates.not(Predicates.equalTo(child)), inRangePredicate, inCoverage);
+ return Iterables.filter(result, predicateFilter);
+ }
+}

Back to the top