From fb7f0867f40d70459176732f706c250e9983bc5a Mon Sep 17 00:00:00 2001
From: Remi Schnekenburger
Date: Thu, 11 Oct 2018 11:10:12 +0200
Subject: [PATCH 1/9] issue_253 - nested execution specification
- new method to get elementAt on execution specification, and access to
nested executions
- command to create a nested execution, that may be refactored with
some commons of the insertExecutionCommand on lifelines
- Add some tests
- handle destruction of nested executions (and their related messages /
nested lifelines in chain)
Some points left:
- adding a nested execution always nudge parent exec, where it should
not if there is enough space
- no side is currently handled for the nested execution representation
- getNestedExecution() may rely on recently introduced getCovered() for
#52
Change-Id: I50589eb0e4ae7b850579d6e1cad5966937dffa4c
Signed-off-by: Remi Schnekenburger
---
.../AnchorsModel.notation | 28 ++-
.../AnchorsModel.uml | 16 +-
.../sequence/figure/LifelineBodyFigure.java | 17 +-
...cutionSpecificationCreationEditPolicy.java | 111 ++++++++++
.../policies/NoPapyrusEditPolicyProvider.java | 3 +
...ecutionSpecificationBorderItemLocator.java | 43 +---
.../model/seqd.ecore | 44 ++++
.../model/seqd.genmodel | 16 ++
.../model/SequenceDiagramPackage.java | 117 +++++++++-
.../internal/model/impl/MExecutionImpl.java | 126 ++++++++++-
.../impl/SequenceDiagramPackageImpl.java | 88 ++++++++
.../uml/interaction/model/MExecution.java | 46 ++++
.../InsertNestedExecutionCommand.java | 200 ++++++++++++++++++
.../commands/RemoveExecutionCommand.java | 5 +
.../model/spi/impl/DefaultDiagramHelper.java | 33 +++
.../interaction/model/spi/DiagramHelper.java | 17 ++
.../model/tests/AnchorsModel.notation | 4 +
.../interaction/model/tests/AnchorsModel.uml | 7 +-
.../model/tests/MExecutionTest.java | 78 ++++++-
.../model/tests/MLifelineTest.java | 15 +-
.../interaction/model/tests/MMessageTest.java | 4 +-
21 files changed, 960 insertions(+), 58 deletions(-)
create mode 100644 plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/ExecutionSpecificationCreationEditPolicy.java
create mode 100644 plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java
diff --git a/examples/LightweightSequenceExample/AnchorsModel.notation b/examples/LightweightSequenceExample/AnchorsModel.notation
index 5a2972d5..6bfa7eee 100644
--- a/examples/LightweightSequenceExample/AnchorsModel.notation
+++ b/examples/LightweightSequenceExample/AnchorsModel.notation
@@ -25,6 +25,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -43,14 +55,20 @@
-
-
+
+
-
-
+
+
+
+
+
+
+
+
@@ -178,7 +196,7 @@
-
+
diff --git a/examples/LightweightSequenceExample/AnchorsModel.uml b/examples/LightweightSequenceExample/AnchorsModel.uml
index 67f8943a..1852aa10 100644
--- a/examples/LightweightSequenceExample/AnchorsModel.uml
+++ b/examples/LightweightSequenceExample/AnchorsModel.uml
@@ -4,14 +4,26 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.papyrus.uml.diagram.sequence.figure/src/org/eclipse/papyrus/uml/diagram/sequence/figure/LifelineBodyFigure.java b/plugins/org.eclipse.papyrus.uml.diagram.sequence.figure/src/org/eclipse/papyrus/uml/diagram/sequence/figure/LifelineBodyFigure.java
index 25cc2445..a6d6d53e 100644
--- a/plugins/org.eclipse.papyrus.uml.diagram.sequence.figure/src/org/eclipse/papyrus/uml/diagram/sequence/figure/LifelineBodyFigure.java
+++ b/plugins/org.eclipse.papyrus.uml.diagram.sequence.figure/src/org/eclipse/papyrus/uml/diagram/sequence/figure/LifelineBodyFigure.java
@@ -16,7 +16,6 @@
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.Polyline;
import org.eclipse.draw2d.geometry.Point;
-import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
@@ -97,11 +96,6 @@ protected ConnectionAnchor createBodyAnchor(int height) {
return new LifelineBodyAnchor(this, height);
}
- @Override
- public PointList getPolygonPoints() {
- return super.getPolygonPoints();
- }
-
@Override
public ConnectionAnchor getSourceConnectionAnchorAt(Point p) {
// This method would be used to retrieve an Anchor from a Request (Create, Reconnect). However,
@@ -143,4 +137,15 @@ public void setDefaultAnchorDistance(int distance) {
this.defaultAnchorDistance = distance;
}
+ @SuppressWarnings("deprecation")
+ @Override
+ public Rectangle getClientArea(Rectangle rect) {
+ rect.setBounds(getBounds());
+ rect.crop(getInsets());
+ if (useLocalCoordinates()) {
+ rect.setLocation(0, 0);
+ }
+ return rect;
+ }
+
}
diff --git a/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/ExecutionSpecificationCreationEditPolicy.java b/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/ExecutionSpecificationCreationEditPolicy.java
new file mode 100644
index 00000000..4547794b
--- /dev/null
+++ b/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/ExecutionSpecificationCreationEditPolicy.java
@@ -0,0 +1,111 @@
+/*****************************************************************************
+ * Copyright (c) 2018 EclipseSource and others.
+ *
+ * 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:
+ * R. Schnekenburger - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.diagram.sequence.runtime.internal.edit.policies;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.gmf.runtime.emf.type.core.IElementType;
+import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
+import org.eclipse.gmf.runtime.notation.Shape;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.uml.diagram.sequence.runtime.util.SequenceTypeSwitch;
+import org.eclipse.papyrus.uml.interaction.model.MElement;
+import org.eclipse.papyrus.uml.interaction.model.MExecution;
+import org.eclipse.papyrus.uml.interaction.model.MInteraction;
+import org.eclipse.papyrus.uml.interaction.model.MLifeline;
+import org.eclipse.papyrus.uml.interaction.model.MObject;
+import org.eclipse.papyrus.uml.interaction.model.util.SequenceDiagramSwitch;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.ExecutionSpecification;
+
+/**
+ * ExecutionSpecification creation edit policy based on the Logical Model.
+ */
+public class ExecutionSpecificationCreationEditPolicy extends LogicalModelCreationEditPolicy {
+
+ @Override
+ protected Optional getCreationCommand(MInteraction interaction,
+ Element parentElement, View parentView, Point location, Dimension size, IElementType type) {
+
+ Optional mExecution = Optional.empty();
+
+ ExecutionSpecification exec = (ExecutionSpecification)parentElement;
+ for (MLifeline lifeline : interaction.getLifelines()) {
+ Optional execution = lifeline.getExecution(exec);
+ if (execution.isPresent()) {
+ mExecution = execution;
+ }
+ }
+
+ if (!mExecution.isPresent()) {
+ return Optional.empty();
+ }
+
+ class CommandSwitch extends SequenceDiagramSwitch {
+
+ @Override
+ @SuppressWarnings("hiding")
+ public Command caseMExecution(MExecution execution) {
+ return new SequenceTypeSwitch() {
+ @Override
+ public Command caseExecutionSpecification(IElementType type) {
+ EClass eClass = type.getEClass();
+ Optional> before = execution.elementAt(location.y());
+ int offset = location.y();
+
+ if (before.isPresent()) {
+ // Get the bottom of the before element
+ OptionalInt bottom = before.get().getBottom();
+ if (bottom.isPresent()) {
+ int relativeBottom = bottom.getAsInt()
+ - getLayoutHelper().getTop((Shape)parentView);
+ offset = offset - relativeBottom;
+ } else {
+ // If it doesn't have a bottom, then ignore it
+ before = Optional.empty();
+ }
+ }
+
+ return execution.insertNestedExecutionAfter(before.orElse(execution), offset,
+ size != null ? size.height : 40, eClass);
+ }
+
+ @Override
+ public Command caseAsyncMessage(IHintedType type) {
+ return null;
+ }
+
+ @Override
+ public Command defaultCase(Object object) {
+ return CommandSwitch.super.caseMExecution(execution);
+ }
+ }.doSwitch(type);
+ }
+
+ @Override
+ public Command defaultCase(MObject object) {
+ return UnexecutableCommand.INSTANCE;
+ }
+ }
+
+ return mExecution.map(new CommandSwitch()::doSwitch);
+ }
+
+}
diff --git a/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/NoPapyrusEditPolicyProvider.java b/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/NoPapyrusEditPolicyProvider.java
index 60e6328d..20519693 100644
--- a/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/NoPapyrusEditPolicyProvider.java
+++ b/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/edit/policies/NoPapyrusEditPolicyProvider.java
@@ -27,6 +27,7 @@
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper;
import org.eclipse.papyrus.uml.diagram.sequence.runtime.internal.Activator;
+import org.eclipse.papyrus.uml.diagram.sequence.runtime.internal.edit.parts.ExecutionSpecificationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.runtime.internal.edit.parts.InteractionCompartmentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.runtime.internal.edit.parts.LifelineBodyEditPart;
import org.eclipse.papyrus.uml.interaction.model.spi.ViewTypes;
@@ -55,6 +56,8 @@ public NoPapyrusEditPolicyProvider() {
LifelineCreationEditPolicy::new);
substitute(InteractionCompartmentEditPart.class, EditPolicyRoles.CREATION_ROLE,
InteractionCreationEditPolicy::new);
+ substitute(ExecutionSpecificationEditPart.class, EditPolicyRoles.CREATION_ROLE,
+ ExecutionSpecificationCreationEditPolicy::new);
// Diagram assistant edit policies
substitute(LifelineBodyEditPart.class, EditPolicyRoles.POPUPBAR_ROLE,
diff --git a/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/locators/ExecutionSpecificationBorderItemLocator.java b/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/locators/ExecutionSpecificationBorderItemLocator.java
index b24f24f9..b9913abe 100644
--- a/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/locators/ExecutionSpecificationBorderItemLocator.java
+++ b/plugins/org.eclipse.papyrus.uml.diagram.sequence.runtime/src/org/eclipse/papyrus/uml/diagram/sequence/runtime/internal/locators/ExecutionSpecificationBorderItemLocator.java
@@ -15,9 +15,7 @@
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
-import org.eclipse.draw2d.geometry.Translatable;
import org.eclipse.gmf.runtime.diagram.ui.figures.IBorderItemLocator;
-import org.eclipse.papyrus.uml.diagram.sequence.figure.LifelineHeaderFigure;
//TODO Support a side (Current it is always to the right side)
public class ExecutionSpecificationBorderItemLocator implements IBorderItemLocator {
@@ -32,44 +30,16 @@ public ExecutionSpecificationBorderItemLocator(IFigure figure) {
@Override
public void relocate(IFigure borderExecutionSpecification) {
- Point location = new Point(0, getConstraint().y);
- translateToInteraction(location);
- int width = borderExecutionSpecification.getBounds().width;
+ Rectangle parentExecution = parentExecutionSpecification.getBounds().getCopy();
- location.translate(-width / 2., 0); // Translate to the right border of the parent
+ Point location = new Point(parentExecution.getRight().x() - getConstraint().width / 2,
+ parentExecution.getTop().y + getConstraint().y);
Rectangle newBounds = getConstraint().getCopy();
newBounds.setLocation(location);
borderExecutionSpecification.setBounds(newBounds);
}
- /**
- *
- * The border execution specification coordinates are relative to this.figure (Which is also an execution
- * specification). The result coordinates must be relative to the interaction (Lifeline's parent).
- *
- *
- * This is required because neither the Lifeline nor the Execution Specification has an X/Y Layout
- * Compartment (Only the interaction does).
- *
- *
- * @param bounds
- * The bounds to be translated to the lifeline's parent coordinates system
- */
- // TODO: Is there a way to make this more generic, e.g. by identifying the first non-null, non-delegating
- // layout?
- private void translateToInteraction(Translatable bounds) {
- IFigure parent = parentExecutionSpecification;
- while (parent != null) {
- parent.translateToParent(bounds);
- if (parent instanceof LifelineHeaderFigure) {
- parent.translateToParent(bounds);
- return;
- }
- parent = parent.getParent();
- }
- }
-
private Rectangle getConstraint() {
return this.constraint;
}
@@ -81,7 +51,12 @@ public void setConstraint(Rectangle constraint) {
@Override
public Rectangle getValidLocation(Rectangle proposedLocation, IFigure borderItem) {
- return proposedLocation; // TODO Shift x and limit to the height of the parent
+ Rectangle parentExecution = parentExecutionSpecification.getBounds().getCopy();
+ Point location = new Point(parentExecution.getRight().x - getConstraint().width / 2,
+ parentExecution.getTop().y + getConstraint().y);
+ Rectangle newBounds = getConstraint().getCopy();
+ newBounds.setLocation(location);
+ return newBounds;
}
@Override
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore b/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore
index f0edd8e2..c4d33bfc 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore
@@ -446,6 +446,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.genmodel b/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.genmodel
index a7be60a1..0da7829d 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.genmodel
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.genmodel
@@ -149,6 +149,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java
index f304ffed..24b04cae 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java
@@ -802,6 +802,41 @@ public interface SequenceDiagramPackage extends EPackage {
*/
int MEXECUTION___GET_DIAGRAM_VIEW = MELEMENT_OPERATION_COUNT + 1;
+ /**
+ * The operation id for the 'Insert Nested Execution After' operation.
+ *
+ *
+ * @generated
+ * @ordered
+ */
+ int MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ELEMENT = MELEMENT_OPERATION_COUNT + 2;
+
+ /**
+ * The operation id for the 'Insert Nested Execution After' operation.
+ *
+ *
+ * @generated
+ * @ordered
+ */
+ int MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ECLASS = MELEMENT_OPERATION_COUNT + 3;
+
+ /**
+ * The operation id for the 'Element At' operation.
+ *
+ * @generated
+ * @ordered
+ */
+ int MEXECUTION___ELEMENT_AT__INT = MELEMENT_OPERATION_COUNT + 4;
+
+ /**
+ * The operation id for the 'Get Nested Executions' operation.
+ *
+ * @generated
+ * @ordered
+ */
+ int MEXECUTION___GET_NESTED_EXECUTIONS = MELEMENT_OPERATION_COUNT + 5;
+
/**
* The number of operations of the 'MExecution' class.
@@ -809,7 +844,7 @@ public interface SequenceDiagramPackage extends EPackage {
* @generated
* @ordered
*/
- int MEXECUTION_OPERATION_COUNT = MELEMENT_OPERATION_COUNT + 2;
+ int MEXECUTION_OPERATION_COUNT = MELEMENT_OPERATION_COUNT + 6;
/**
* The meta object id for the
@@ -2324,6 +2359,52 @@ public interface SequenceDiagramPackage extends EPackage {
*/
EOperation getMExecution__GetDiagramView();
+ /**
+ * Returns the meta object for the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement, int, int, org.eclipse.uml2.uml.Element)
+ * Insert Nested Execution After}' operation.
+ *
+ * @return the meta object for the 'Insert Nested Execution After' operation.
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement,
+ * int, int, org.eclipse.uml2.uml.Element)
+ * @generated
+ */
+ EOperation getMExecution__InsertNestedExecutionAfter__MElement_int_int_Element();
+
+ /**
+ * Returns the meta object for the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement, int, int, org.eclipse.emf.ecore.EClass)
+ * Insert Nested Execution After}' operation.
+ *
+ * @return the meta object for the 'Insert Nested Execution After' operation.
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement,
+ * int, int, org.eclipse.emf.ecore.EClass)
+ * @generated
+ */
+ EOperation getMExecution__InsertNestedExecutionAfter__MElement_int_int_EClass();
+
+ /**
+ * Returns the meta object for the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#elementAt(int) Element At}'
+ * operation.
+ *
+ * @return the meta object for the 'Element At' operation.
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#elementAt(int)
+ * @generated
+ */
+ EOperation getMExecution__ElementAt__int();
+
+ /**
+ * Returns the meta object for the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#getNestedExecutions() Get Nested
+ * Executions}' operation.
+ *
+ * @return the meta object for the 'Get Nested Executions' operation.
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#getNestedExecutions()
+ * @generated
+ */
+ EOperation getMExecution__GetNestedExecutions();
+
/**
* Returns the meta object for class '{@link org.eclipse.papyrus.uml.interaction.model.MOccurrence
* MOccurrence}'.
@@ -3125,6 +3206,40 @@ interface Literals {
*/
EOperation MEXECUTION___GET_DIAGRAM_VIEW = eINSTANCE.getMExecution__GetDiagramView();
+ /**
+ * The meta object literal for the 'Insert Nested Execution After' operation.
+ *
+ * @generated
+ */
+ EOperation MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ELEMENT = eINSTANCE
+ .getMExecution__InsertNestedExecutionAfter__MElement_int_int_Element();
+
+ /**
+ * The meta object literal for the 'Insert Nested Execution After' operation.
+ *
+ * @generated
+ */
+ EOperation MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ECLASS = eINSTANCE
+ .getMExecution__InsertNestedExecutionAfter__MElement_int_int_EClass();
+
+ /**
+ * The meta object literal for the 'Element At' operation.
+ *
+ *
+ * @generated
+ */
+ EOperation MEXECUTION___ELEMENT_AT__INT = eINSTANCE.getMExecution__ElementAt__int();
+
+ /**
+ * The meta object literal for the 'Get Nested Executions' operation.
+ *
+ * @generated
+ */
+ EOperation MEXECUTION___GET_NESTED_EXECUTIONS = eINSTANCE.getMExecution__GetNestedExecutions();
+
/**
* The meta object literal for the
* '{@link org.eclipse.papyrus.uml.interaction.internal.model.impl.MOccurrenceImpl
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java
index a2935d52..6ebb429b 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java
@@ -12,19 +12,31 @@
*/
package org.eclipse.papyrus.uml.interaction.internal.model.impl;
+import static org.eclipse.papyrus.uml.interaction.graph.GraphPredicates.covers;
+
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
+import java.util.Stack;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.gmf.runtime.notation.Shape;
+import org.eclipse.papyrus.uml.interaction.graph.Vertex;
import org.eclipse.papyrus.uml.interaction.internal.model.SequenceDiagramPackage;
+import org.eclipse.papyrus.uml.interaction.internal.model.commands.InsertNestedExecutionCommand;
import org.eclipse.papyrus.uml.interaction.internal.model.commands.RemoveExecutionCommand;
+import org.eclipse.papyrus.uml.interaction.model.CreationCommand;
+import org.eclipse.papyrus.uml.interaction.model.MElement;
import org.eclipse.papyrus.uml.interaction.model.MExecution;
-import org.eclipse.papyrus.uml.interaction.model.MLifeline;
import org.eclipse.papyrus.uml.interaction.model.MOccurrence;
+import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ExecutionSpecification;
+import org.eclipse.uml2.uml.OccurrenceSpecification;
/**
* An implementation of the model object 'MExecution'.
+ *
+ * @generated NOT
+ */
+ @Override
+ public CreationCommand insertNestedExecutionAfter(MElement> before, int offset,
+ int height, Element specification) {
+ return new InsertNestedExecutionCommand(this, before, offset, height, specification);
+ }
+
+ /**
+ *
+ *
+ * @generated NOT
+ */
+ @Override
+ public CreationCommand insertNestedExecutionAfter(MElement> before, int offset,
+ int height, EClass metaclass) {
+ return new InsertNestedExecutionCommand(this, before, offset, height, metaclass);
+ }
+
+ /**
+ *
+ *
+ * @generated NOT
+ */
+ @Override
+ public Optional> elementAt(int offset) {
+ int top = layoutHelper().getTop(getShape(getElement()));
+ int absoluteOffset = top + offset;
+
+ Predicate> isAtOrAbove = e -> e.getBottom().orElse(Integer.MAX_VALUE) <= absoluteOffset;
+
+ Optional extends MElement extends Element>> result = getVertex().flatMap(vtx -> //
+ vtx.successors().sequential().filter(covers(getOwner().getElement())) //
+ .map(Vertex::getInteractionElement) //
+ .map(getInteraction()::getElement) //
+ .filter(Optional::isPresent).map(Optional::get) //
+ .filter(isAtOrAbove)//
+ .reduce((a, b) -> b)// last element
+ );
+
+ return Optional.ofNullable(result.orElse(null));
+ }
+
+ /**
+ *
+ *
+ * @generated NOT
+ */
+ @SuppressWarnings("boxing")
+ @Override
+ public List getNestedExecutions() {
+ List nestedExecutions = new ArrayList<>();
+ // browse all executions on lifeline after the start of this execution and before the end of this
+ // execution
+
+ List> occurences = getOccurenceSpecifications();
+
+ int start = getStart().map(occ -> occurences.indexOf(occ)).orElse(-1);
+ int finish = getFinish().map(occ -> occurences.indexOf(occ)).orElse(-1);
+ if (start != -1 && finish != -1 && finish - start > 1) {
+ List> executionOccurences = occurences.subList(start, finish);
+
+ Stack stack = new Stack<>();
+ for (MOccurrence occurence : executionOccurences) {
+ // check if it starts a new occurrence. If yes, adds it on top of the stack
+ // if it finishes, removes the finished execution from the stack
+ occurence.getFinishedExecution().ifPresent(__ -> {
+ if (!stack.isEmpty()) {
+ stack.pop();
+ }
+ });
+ if (occurence.getStartedExecution().isPresent()) {
+ MExecution execution = occurence.getStartedExecution().get();
+ // if current owner => this, then this execution should be added to the nested executions
+ if (!stack.empty() && stack.peek() == this) {
+ nestedExecutions.add(execution);
+ }
+ stack.push(execution);
+ }
+ }
+ }
+ return nestedExecutions;
+ }
+
+ protected List> getOccurenceSpecifications() {
+ List> orderedCoveredBys = getInteraction().getElement().getFragments().stream()
+ .filter(frg -> frg.getCovereds().contains(getOwner().getElement())) //
+ .filter(OccurrenceSpecification.class::isInstance) //
+ .map(el -> getInteraction().getElement(el)) //
+ .filter(e -> e.isPresent()) //
+ .map(e -> MOccurrence.class.cast(e.get())) //
+ .collect(Collectors.toList());
+ return orderedCoveredBys;
+ }
+
/**
*
*
@@ -151,6 +261,16 @@ public Object eInvoke(int operationID, EList> arguments) throws InvocationTarg
return getOwner();
case SequenceDiagramPackage.MEXECUTION___GET_DIAGRAM_VIEW:
return getDiagramView();
+ case SequenceDiagramPackage.MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ELEMENT:
+ return insertNestedExecutionAfter((MElement>)arguments.get(0), (Integer)arguments.get(1),
+ (Integer)arguments.get(2), (Element)arguments.get(3));
+ case SequenceDiagramPackage.MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ECLASS:
+ return insertNestedExecutionAfter((MElement>)arguments.get(0), (Integer)arguments.get(1),
+ (Integer)arguments.get(2), (EClass)arguments.get(3));
+ case SequenceDiagramPackage.MEXECUTION___ELEMENT_AT__INT:
+ return elementAt((Integer)arguments.get(0));
+ case SequenceDiagramPackage.MEXECUTION___GET_NESTED_EXECUTIONS:
+ return getNestedExecutions();
}
return super.eInvoke(operationID, arguments);
}
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java
index ea3a5ef4..3e952910 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java
@@ -716,6 +716,46 @@ public EOperation getMExecution__GetDiagramView() {
return mExecutionEClass.getEOperations().get(1);
}
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getMExecution__InsertNestedExecutionAfter__MElement_int_int_Element() {
+ return mExecutionEClass.getEOperations().get(2);
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getMExecution__InsertNestedExecutionAfter__MElement_int_int_EClass() {
+ return mExecutionEClass.getEOperations().get(3);
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getMExecution__ElementAt__int() {
+ return mExecutionEClass.getEOperations().get(4);
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getMExecution__GetNestedExecutions() {
+ return mExecutionEClass.getEOperations().get(5);
+ }
+
/**
*
*
@@ -1123,6 +1163,12 @@ public void createPackageContents() {
createEAttribute(mExecutionEClass, MEXECUTION__FINISH);
createEOperation(mExecutionEClass, MEXECUTION___GET_OWNER);
createEOperation(mExecutionEClass, MEXECUTION___GET_DIAGRAM_VIEW);
+ createEOperation(mExecutionEClass,
+ MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ELEMENT);
+ createEOperation(mExecutionEClass,
+ MEXECUTION___INSERT_NESTED_EXECUTION_AFTER__MELEMENT_INT_INT_ECLASS);
+ createEOperation(mExecutionEClass, MEXECUTION___ELEMENT_AT__INT);
+ createEOperation(mExecutionEClass, MEXECUTION___GET_NESTED_EXECUTIONS);
mOccurrenceEClass = createEClass(MOCCURRENCE);
createEAttribute(mOccurrenceEClass, MOCCURRENCE__COVERED);
@@ -1621,6 +1667,48 @@ public void initializePackageContents() {
g1.getETypeArguments().add(g2);
initEOperation(op, g1);
+ op = initEOperation(getMExecution__InsertNestedExecutionAfter__MElement_int_int_Element(), null,
+ "insertNestedExecutionAfter", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ g1 = createEGenericType(this.getMElement());
+ g2 = createEGenericType();
+ g1.getETypeArguments().add(g2);
+ addEParameter(op, g1, "before", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, ecorePackage.getEInt(), "offset", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, ecorePackage.getEInt(), "height", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, theUMLPackage.getElement(), "specification", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ g1 = createEGenericType(this.getCreationCommand());
+ g2 = createEGenericType(theUMLPackage.getExecutionSpecification());
+ g1.getETypeArguments().add(g2);
+ initEOperation(op, g1);
+
+ op = initEOperation(getMExecution__InsertNestedExecutionAfter__MElement_int_int_EClass(), null,
+ "insertNestedExecutionAfter", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ g1 = createEGenericType(this.getMElement());
+ g2 = createEGenericType();
+ g1.getETypeArguments().add(g2);
+ addEParameter(op, g1, "before", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, ecorePackage.getEInt(), "offset", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, ecorePackage.getEInt(), "height", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, theEcorePackage.getEClass(), "metaclass", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ g1 = createEGenericType(this.getCreationCommand());
+ g2 = createEGenericType(theUMLPackage.getExecutionSpecification());
+ g1.getETypeArguments().add(g2);
+ initEOperation(op, g1);
+
+ op = initEOperation(getMExecution__ElementAt__int(), null, "elementAt", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ addEParameter(op, ecorePackage.getEInt(), "offset", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ g1 = createEGenericType(this.getOptional());
+ g2 = createEGenericType(this.getMElement());
+ g1.getETypeArguments().add(g2);
+ g3 = createEGenericType();
+ g2.getETypeArguments().add(g3);
+ g4 = createEGenericType(theUMLPackage.getElement());
+ g3.setEUpperBound(g4);
+ initEOperation(op, g1);
+
+ initEOperation(getMExecution__GetNestedExecutions(), this.getMExecution(), "getNestedExecutions", 0, //$NON-NLS-1$
+ -1, IS_UNIQUE, IS_ORDERED);
+
initEClass(mOccurrenceEClass, MOccurrence.class, "MOccurrence", IS_ABSTRACT, !IS_INTERFACE, //$NON-NLS-1$
IS_GENERATED_INSTANCE_CLASS);
g1 = createEGenericType(this.getOptional());
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MExecution.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MExecution.java
index f989838e..25465e0e 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MExecution.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MExecution.java
@@ -12,9 +12,12 @@
*/
package org.eclipse.papyrus.uml.interaction.model;
+import java.util.List;
import java.util.Optional;
+import org.eclipse.emf.ecore.EClass;
import org.eclipse.gmf.runtime.notation.Shape;
+import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ExecutionSpecification;
/**
@@ -85,4 +88,47 @@ public interface MExecution extends MElement {
@Override
Optional getDiagramView();
+ /**
+ *
+ *
+ * @model dataType="org.eclipse.papyrus.uml.interaction.model.CreationCommand<org.eclipse.uml2.uml.ExecutionSpecification>"
+ * required="true" beforeRequired="true" offsetRequired="true" heightRequired="true"
+ * specificationRequired="true"
+ * @generated
+ */
+ CreationCommand insertNestedExecutionAfter(MElement> before, int offset,
+ int height, Element specification);
+
+ /**
+ *
+ *
+ * @model dataType="org.eclipse.papyrus.uml.interaction.model.CreationCommand<org.eclipse.uml2.uml.ExecutionSpecification>"
+ * required="true" beforeRequired="true" offsetRequired="true" heightRequired="true"
+ * metaclassRequired="true"
+ * @generated
+ */
+ CreationCommand insertNestedExecutionAfter(MElement> before, int offset,
+ int height, EClass metaclass);
+
+ /**
+ * Query the element covering this
+ * execution that is at, or the nearest element before, a given y-coordinate {@code offset}.
+ *
+ * @param offset
+ * an offset in the y axis on the execution border. Should be non-negative
+ * @model dataType="org.eclipse.papyrus.uml.interaction.model.Optional<org.eclipse.papyrus.uml.interaction.model.MElement<?
+ * extends org.eclipse.uml2.uml.Element>>" required="true" offsetRequired="true"
+ * @generated
+ */
+ Optional> elementAt(int offset);
+
+ /**
+ *
+ *
+ * @model kind="operation"
+ * @generated
+ */
+ List getNestedExecutions();
+
} // MExecution
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java
new file mode 100644
index 00000000..fc77cb4d
--- /dev/null
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java
@@ -0,0 +1,200 @@
+/*****************************************************************************
+ * Copyright (c) 2018 EclipseSource and others.
+ *
+ * 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:
+ * EclipseSource - Initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.interaction.internal.model.commands;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.function.Function;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.gmf.runtime.notation.Shape;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.uml.interaction.graph.Vertex;
+import org.eclipse.papyrus.uml.interaction.internal.model.impl.MExecutionImpl;
+import org.eclipse.papyrus.uml.interaction.model.CreationCommand;
+import org.eclipse.papyrus.uml.interaction.model.CreationParameters;
+import org.eclipse.papyrus.uml.interaction.model.MElement;
+import org.eclipse.papyrus.uml.interaction.model.MExecution;
+import org.eclipse.papyrus.uml.interaction.model.spi.DeferredAddCommand;
+import org.eclipse.papyrus.uml.interaction.model.spi.SemanticHelper;
+import org.eclipse.uml2.uml.Action;
+import org.eclipse.uml2.uml.Behavior;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.ExecutionSpecification;
+import org.eclipse.uml2.uml.OccurrenceSpecification;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * An execution specification creation operation.
+ *
+ * @author Christian W. Damus
+ */
+public class InsertNestedExecutionCommand extends ModelCommand implements CreationCommand {
+
+ private final MElement> before;
+
+ private final int offset;
+
+ private final int height;
+
+ private final Element specification;
+
+ private final EClass eClass;
+
+ private CreationCommand resultCommand;
+
+ /**
+ * Initializes me.
+ *
+ * @param owner
+ * the lifeline on which to create the execution specification
+ * @param before
+ * the element in the sequence after which to create the new execution specification
+ * @param offset
+ * the offset from the reference element at which to create the execution specification
+ * @param height
+ * the height of the execution specification
+ * @param specification
+ * the action or behavior to reference, if any
+ */
+ public InsertNestedExecutionCommand(MExecutionImpl owner, MElement> before, int offset, int height,
+ Element specification) {
+
+ super(owner);
+
+ checkInteraction(before);
+ if (specification != null && !(specification instanceof Action)
+ && !(specification instanceof Behavior)) {
+ throw new IllegalArgumentException("specification is neither action nor behavior"); //$NON-NLS-1$
+ }
+
+ this.before = before;
+ this.offset = offset;
+ this.height = height;
+ this.specification = specification;
+ this.eClass = (specification instanceof Action) ? UMLPackage.Literals.ACTION_EXECUTION_SPECIFICATION
+ : UMLPackage.Literals.BEHAVIOR_EXECUTION_SPECIFICATION;
+ }
+
+ /**
+ * Initializes me.
+ *
+ * @param owner
+ * the lifeline on which to create the execution specification
+ * @param before
+ * the element in the sequence after which to create the new execution specification
+ * @param offset
+ * the offset from the reference element at which to create the execution specification
+ * @param height
+ * the height of the execution specification
+ * @param eClass
+ * the kind of execution specification to create
+ */
+ public InsertNestedExecutionCommand(MExecutionImpl owner, MElement> before, int offset, int height,
+ EClass eClass) {
+
+ super(owner);
+
+ checkInteraction(before);
+ if (!UMLPackage.Literals.EXECUTION_SPECIFICATION.isSuperTypeOf(eClass) || eClass.isAbstract()) {
+ throw new IllegalArgumentException("invalid execution specification type"); //$NON-NLS-1$
+ }
+
+ this.before = before;
+ this.offset = offset;
+ this.height = height;
+ this.specification = null;
+ this.eClass = eClass;
+ }
+
+ @Override
+ public ExecutionSpecification getNewObject() {
+ return (resultCommand == null) ? null : resultCommand.getNewObject();
+ }
+
+ @Override
+ protected Command createCommand() {
+ Vertex reference = vertex(before);
+ if (reference == null) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ OptionalInt referenceY;
+ if (before instanceof MExecution && before == getTarget()) {
+ referenceY = OptionalInt.of(0);
+ } else { // before should be an element on the execution itself.
+ referenceY = OptionalInt.of(
+ layoutHelper().getBottom(reference).getAsInt() - layoutHelper().getTop(getTargetView()));
+ }
+
+ if (!referenceY.isPresent()) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ MElement extends Element> insertionPoint = normalizeFragmentInsertionPoint(before);
+ Function paramsFactory = CreationParameters::after;
+
+ if (insertionPoint == getTarget()) {
+ // Insert before the first covering fragment, if any
+ Optional> covering = Optional.of(((MExecution)insertionPoint));
+ if (covering.isPresent()) {
+ insertionPoint = covering.get();
+ paramsFactory = CreationParameters::after;
+ }
+ }
+
+ SemanticHelper semantics = semanticHelper();
+ CreationParameters execParams = paramsFactory.apply(insertionPoint.getElement());
+ execParams.setEClass(eClass);
+ resultCommand = semantics.createExecutionSpecification(specification, execParams);
+ CreationParameters startParams = CreationParameters.before(resultCommand);
+ CreationCommand start = semantics.createStart(resultCommand, startParams);
+ CreationParameters finishParams = CreationParameters.after(resultCommand);
+ CreationCommand finish = semantics.createFinish(resultCommand, finishParams);
+
+ // Create these elements in the interaction
+ Command result = resultCommand.chain(start).chain(finish);
+
+ // Add them to the lifeline, too
+ result = result.chain(new DeferredAddCommand(getTarget().getOwner().getElement(),
+ UMLPackage.Literals.LIFELINE__COVERED_BY, start, resultCommand, finish));
+
+ result = result.chain(diagramHelper().createNestedExecutionShape(resultCommand, getTargetView(),
+ referenceY.getAsInt() + offset, height));
+
+ // Now we have commands to add the execution specification. But, first we must make
+ // room for it in the diagram. Nudge the element that will follow the new execution
+ int spaceAdded = offset + height;
+ Optional makeSpace = getTarget().getOwner().following(insertionPoint).map(el -> {
+ return el.nudge(spaceAdded);
+ });
+ if (makeSpace.isPresent()) {
+ result = makeSpace.get().chain(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the target shape for the creation of the execution. In our case, this should be the view
+ * representing the body.
+ *
+ * @return the view that represents the body of the lifeline.
+ */
+ protected Shape getTargetView() {
+ View executionView = getTarget().getDiagramView().get();
+ return Shape.class.cast(executionView);
+ }
+}
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveExecutionCommand.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveExecutionCommand.java
index 8b5f1d1c..625f6522 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveExecutionCommand.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveExecutionCommand.java
@@ -84,6 +84,11 @@ protected Command createCommand() {
messagesToRemove.forEach(
m -> removalCommands.add(new RemoveMessageCommand((MMessageImpl)m, getTarget(), false)));
+ /* remove nested executions */
+ // List> removeNestedExecutions = new ArrayList<>();
+ execution.getNestedExecutions().forEach(
+ nested -> removalCommands.add(new RemoveExecutionCommand((MExecutionImpl)nested, false)));
+
/* semantics */
SemanticHelper semantics = semanticHelper();
removalCommands.add(semantics.deleteExecutionSpecification(execution.getElement()));
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/DefaultDiagramHelper.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/DefaultDiagramHelper.java
index 6e3e835e..2b9f191a 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/DefaultDiagramHelper.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/DefaultDiagramHelper.java
@@ -214,6 +214,39 @@ public CreationCommand createExecutionShape(Supplier extends ExecutionS
NotationPackage.Literals.VIEW__PERSISTED_CHILDREN);
return new DeferredCreateCommand<>(Shape.class, editingDomain, parameters, shape);
}
+
+ @Override
+ public CreationCommand createNestedExecutionShape(
+ Supplier extends ExecutionSpecification> execution, Shape parentExecution, int yPosition,
+ int height) {
+ Supplier shape = () -> {
+ LayoutConstraint llBounds = parentExecution.getLayoutConstraint();
+ int width = 0;
+ if (Size.class.isInstance(llBounds)) {
+ width = Size.class.cast(llBounds).getWidth();
+ }
+ int execWidth = layoutHelper().getConstraints()
+ .getMinimumWidth(ViewTypes.EXECUTION_SPECIFICATION);
+
+ Shape result = NotationFactory.eINSTANCE.createShape();
+ result.setType(ViewTypes.EXECUTION_SPECIFICATION);
+ result.setElement(execution.get());
+
+ Bounds bounds = NotationFactory.eINSTANCE.createBounds();
+ bounds.setX((width - execWidth) / 2); // Relative to the parent
+ bounds.setY(yPosition); // Relative to parent (already the case for yPosition)
+ bounds.setWidth(execWidth);
+ bounds.setHeight(height);
+ result.setLayoutConstraint(bounds);
+
+ return result;
+ };
+
+ CreationParameters parameters = CreationParameters.in(parentExecution,
+ NotationPackage.Literals.VIEW__PERSISTED_CHILDREN);
+ return new DeferredCreateCommand<>(Shape.class, editingDomain, parameters, shape);
+ }
+
@Override
public CreationCommand createDestructionOccurrenceShape(Supplier extends MessageEnd> destruction,
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java
index 1b86da03..332ff252 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java
@@ -102,6 +102,23 @@ CreationCommand createLifelineShape(Supplier extends Lifeline> lifeline
CreationCommand createExecutionShape(Supplier extends ExecutionSpecification> execution,
Shape lifeline, int yPosition, int height);
+/**
+ * Obtain a command to create a shape for the given {@code execution} specification as a child of another
+ * {@link ExecutionSpecification} shape in the diagram.
+ *
+ * @param execution
+ * an execution specification to be visualized in the diagram
+ * @param parentExecution
+ * the execution shape in which to create the {@code execution} shape
+ * @param yPosition
+ * the vertical position of the {@code execution} shape to create
+ * @param height
+ * the vertical extent of the {@code execution} shape to create
+ * @return the execution shape creation command
+ */
+ CreationCommand createNestedExecutionShape(Supplier extends ExecutionSpecification> execution,
+ Shape parentExecution, int yPosition, int height);
+
/**
* Obtain a command to create a shape for the given {@code execution} specification as a child of a
* {@link lifeline} shape in the diagram.
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.notation b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.notation
index 1e931d1d..8d3112fe 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.notation
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.notation
@@ -177,6 +177,10 @@
+
+
+
+
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.uml b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.uml
index cf942fa8..723cb6b8 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.uml
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/AnchorsModel.uml
@@ -37,11 +37,14 @@
-
-
+
+
+
+
+
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
index ff5d7d1a..b3ce88f6 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
@@ -12,15 +12,23 @@
*/
package org.eclipse.papyrus.uml.interaction.model.tests;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
+import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.eclipse.emf.common.command.Command;
import org.eclipse.gmf.runtime.notation.Shape;
+import org.eclipse.papyrus.uml.interaction.model.CreationCommand;
import org.eclipse.papyrus.uml.interaction.model.MExecution;
+import org.eclipse.uml2.uml.ActionExecutionSpecification;
+import org.eclipse.uml2.uml.ExecutionSpecification;
+import org.eclipse.uml2.uml.UMLPackage;
import junit.textui.TestRunner;
@@ -120,7 +128,7 @@ public void testGetElement() {
public void testFollowing() {
super.testFollowing();
- assertThat(getFixture().following().get(), wraps(umlInteraction.getFragment("reply-send")));
+ assertThat(getFixture().following().get(), wraps(umlInteraction.getFragment("Execution1-start")));
}
@Override
@@ -190,6 +198,74 @@ public void testGetDiagramView() {
assertThat(getFixture().getDiagramView().get().getType(), is("Shape_Execution_Specification"));
}
+ /**
+ * Tests the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement, int, int, org.eclipse.emf.ecore.EClass)
+ * Insert Nested Execution After}' operation.
+ *
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement,
+ * int, int, org.eclipse.emf.ecore.EClass)
+ * @generated NOT
+ */
+ @SuppressWarnings("boxing")
+ public void testInsertNestedExecutionAfter__MElement_int_int_EClass() {
+
+ assertThat(getFixture().getNestedExecutions().size(), equalTo(1));
+ CreationCommand command = getFixture().insertNestedExecutionAfter(
+ getFixture(), 12, 22, UMLPackage.Literals.ACTION_EXECUTION_SPECIFICATION);
+
+ assertThat(command, executable());
+ ExecutionSpecification execSpec = create(command);
+ MExecution exec = getFixture().getOwner().getExecution(execSpec).get();
+
+ assertThat(exec.getOwner(), is(getFixture().getOwner()));
+ assertThat(exec.getTop().getAsInt(), is(104)); // top of the nesting exec: 92, +offset: 12
+ assertThat(exec.getBottom().getAsInt(), is(126)); // length = 22
+ assertThat(exec.getElement(), instanceOf(ActionExecutionSpecification.class));
+
+ // We didn't actually supply the action, as such
+ assertThat(((ActionExecutionSpecification)exec.getElement()).getAction(), nullValue());
+ assertThat(getFixture().getNestedExecutions().size(), equalTo(2));
+
+ }
+
+ /**
+ * Tests the '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#elementAt(int) Element
+ * At}' operation.
+ *
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#elementAt(int)
+ * @generated NOT
+ */
+ public void testElementAt__int() {
+ assertFalse(getFixture().elementAt(0).isPresent()); // element is itself
+ assertFalse(getFixture().elementAt(49).isPresent()); // element is itself
+ // exactly the fragment start
+ assertThat(getFixture().elementAt(50).get(), wraps(umlInteraction.getFragment("Execution1-start")));
+ // after the fragment start
+ assertThat(getFixture().elementAt(60).get(), wraps(umlInteraction.getFragment("Execution1-start")));
+ // exactly the fragment finish
+ assertThat(getFixture().elementAt(90).get(), wraps(umlInteraction.getFragment("Execution1-finish")));
+ // after the fragment finish
+ assertThat(getFixture().elementAt(120).get(), wraps(umlInteraction.getFragment("Execution1-finish")));
+ // outside of the fragment
+ assertThat(getFixture().elementAt(200).get(), wraps(umlInteraction.getFragment("reply-send")));
+ }
+
+ /**
+ * Tests the '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#getNestedExecutions() Get
+ * Nested Executions}' operation.
+ *
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#getNestedExecutions()
+ * @generated NOT
+ */
+ public void testGetNestedExecutions() {
+ ExecutionSpecification nested = (ExecutionSpecification)umlInteraction.getFragment("Execution1");
+ MExecution mexec = (MExecution)getFixture().getInteraction().getElement(nested).get();
+ assertTrue(getFixture().getNestedExecutions().equals(Arrays.asList(mexec)));
+
+ assertTrue(mexec.getNestedExecutions().isEmpty());
+ }
+
@Override
public void testRemove() {
MExecution execution = getFixture();
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
index 184e0915..d4e362cb 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
@@ -288,6 +288,12 @@ public void testFollowing__MElement() {
Optional> following = getFixture().following(end.get());
assertThat(following, isPresent(wraps(umlInteraction.getFragment("ActionExecutionSpecification1"))));
following = getFixture().following(following.get());
+ assertThat(following, isPresent(wraps(umlInteraction.getFragment("Execution1-start"))));
+ following = getFixture().following(following.get());
+ assertThat(following, isPresent(wraps(umlInteraction.getFragment("Execution1"))));
+ following = getFixture().following(following.get());
+ assertThat(following, isPresent(wraps(umlInteraction.getFragment("Execution1-finish"))));
+ following = getFixture().following(following.get());
assertThat(following, isPresent(wraps(umlInteraction.getFragment("reply-send"))));
following = getFixture().following(following.get());
assertThat(following, not(isPresent()));
@@ -307,12 +313,17 @@ public void testPreceding__MElement() {
Assume.assumeThat(end, isPresent());
Optional> preceding = getFixture().preceding(end.get());
+ assertThat(preceding, isPresent(wraps(umlInteraction.getFragment("Execution1-finish"))));
+ preceding = getFixture().preceding(preceding.get());
+ assertThat(preceding, isPresent(wraps(umlInteraction.getFragment("Execution1"))));
+ preceding = getFixture().preceding(preceding.get());
+ assertThat(preceding, isPresent(wraps(umlInteraction.getFragment("Execution1-start"))));
+ preceding = getFixture().preceding(preceding.get());
assertThat(preceding, isPresent(wraps(umlInteraction.getFragment("ActionExecutionSpecification1"))));
preceding = getFixture().preceding(preceding.get());
assertThat(preceding, isPresent(wraps(umlInteraction.getFragment("request-recv"))));
preceding = getFixture().preceding(preceding.get());
- assertThat(preceding, not(isPresent()));
- }
+ assertThat(preceding, not(isPresent())); }
/**
* Tests the
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MMessageTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MMessageTest.java
index 85a999af..1068b471 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MMessageTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MMessageTest.java
@@ -233,12 +233,12 @@ public void testRemove() {
/* assert semantic preconditions */
assertEquals(2, umlInteraction.getMessages().size());
assertNotNull(umlInteraction.getMessage("request"));
- assertEquals(5, umlInteraction.getFragments().size());
+ assertEquals(8, umlInteraction.getFragments().size());
assertNotNull(umlInteraction.getFragment("request-send"));
assertNotNull(umlInteraction.getFragment("request-recv"));
assertEquals(2, umlInteraction.getLifelines().size());
assertEquals(2, umlInteraction.getLifelines().get(0).getCoveredBys().size());
- assertEquals(3, umlInteraction.getLifelines().get(1).getCoveredBys().size());
+ assertEquals(6, umlInteraction.getLifelines().get(1).getCoveredBys().size());
/* assert diagram preconditions */
assertEquals(2, sequenceDiagram.getEdges().size());
From c76c5f7e0361855ebb8fc92fd6d90f1f45589b45 Mon Sep 17 00:00:00 2001
From: Remi Schnekenburger
Date: Thu, 11 Oct 2018 11:25:45 +0200
Subject: [PATCH 2/9] Issue_253 - nested executions
- Check and update model generation for test and model plugin from
seqd.ecore
- do not update edit plugin (formatting issues with current version on
the server)
Change-Id: I532032620ae40c29412ef113f183709a4cc25b5c
Signed-off-by: Remi Schnekenburger
---
.../internal/model/impl/MLifelineImpl.java | 4 ++--
.../papyrus/uml/interaction/model/MMessage.java | 1 +
.../interaction/model/tests/MExecutionTest.java | 17 +++++++++++++++++
.../interaction/model/tests/MLifelineTest.java | 3 ++-
.../spi/impl/tests/LogicalModelAdapterTest.java | 8 +++-----
.../model/tests/deletion/BasicDeletionTest.java | 2 +-
6 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java
index 4615c3d6..6eedfb7a 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java
@@ -530,9 +530,9 @@ public void eUnset(int featureID) {
public boolean eIsSet(int featureID) {
switch (featureID) {
case SequenceDiagramPackage.MLIFELINE__EXECUTION_OCCURRENCES:
- return (executionOccurrences != null) && !executionOccurrences.isEmpty();
+ return executionOccurrences != null && !executionOccurrences.isEmpty();
case SequenceDiagramPackage.MLIFELINE__EXECUTIONS:
- return (executions != null) && !executions.isEmpty();
+ return executions != null && !executions.isEmpty();
case SequenceDiagramPackage.MLIFELINE__OWNED_DESTRUCTION:
return ownedDestruction != null;
case SequenceDiagramPackage.MLIFELINE__DESTRUCTION:
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MMessage.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MMessage.java
index 0a557ac7..ff29a5ad 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MMessage.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MMessage.java
@@ -13,6 +13,7 @@
package org.eclipse.papyrus.uml.interaction.model;
import java.util.Optional;
+
import org.eclipse.gmf.runtime.notation.Connector;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageEnd;
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
index b3ce88f6..81cf0e0f 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
@@ -29,6 +29,7 @@
import org.eclipse.uml2.uml.ActionExecutionSpecification;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.UMLPackage;
+import org.junit.Ignore;
import junit.textui.TestRunner;
@@ -198,6 +199,22 @@ public void testGetDiagramView() {
assertThat(getFixture().getDiagramView().get().getType(), is("Shape_Execution_Specification"));
}
+ /**
+ * Tests the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement, int, int, org.eclipse.uml2.uml.Element)
+ * Insert Nested Execution After}' operation.
+ *
+ * @see org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement,
+ * int, int, org.eclipse.uml2.uml.Element)
+ * @generated
+ */
+ @Ignore
+ public void testInsertNestedExecutionAfter__MElement_int_int_Element() {
+ // TODO: implement this operation test method
+ // Ensure that you remove @generated or mark it @generated NOT
+ fail();
+ }
+
/**
* Tests the
* '{@link org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement, int, int, org.eclipse.emf.ecore.EClass)
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
index d4e362cb..8f71d651 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
@@ -323,7 +323,8 @@ public void testPreceding__MElement() {
preceding = getFixture().preceding(preceding.get());
assertThat(preceding, isPresent(wraps(umlInteraction.getFragment("request-recv"))));
preceding = getFixture().preceding(preceding.get());
- assertThat(preceding, not(isPresent())); }
+ assertThat(preceding, not(isPresent()));
+ }
/**
* Tests the
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/tests/LogicalModelAdapterTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/tests/LogicalModelAdapterTest.java
index 2c687466..0fd95916 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/tests/LogicalModelAdapterTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/internal/model/spi/impl/tests/LogicalModelAdapterTest.java
@@ -43,15 +43,13 @@ public class LogicalModelAdapterTest {
/**
* Initializes me.
- *
*/
public LogicalModelAdapterTest() {
super();
}
/**
- * Test that the adapter notifies creation of an already existing logical model
- * when the handler is added.
+ * Test that the adapter notifies creation of an already existing logical model when the handler is added.
*/
@Test
public void onLogicalModelCreated_immediate() {
@@ -64,8 +62,8 @@ public void onLogicalModelCreated_immediate() {
}
/**
- * Test that the adapter notifies creation of a new logical model when it is
- * created when the handler is added.
+ * Test that the adapter notifies creation of a new logical model when it is created when the handler is
+ * added.
*/
@Test
public void onLogicalModelCreated_new() {
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/model/tests/deletion/BasicDeletionTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/model/tests/deletion/BasicDeletionTest.java
index 6d5fd9cf..4d59b36d 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/model/tests/deletion/BasicDeletionTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src/org/eclipse/papyrus/uml/interaction/model/tests/deletion/BasicDeletionTest.java
@@ -59,7 +59,7 @@ private void executeAndAssertRemoval(RemovalCommand remove,
Assert.fail("Command not executable"); //$NON-NLS-1$
}
/* make sure no duplicates */
- Set> exepcted = new LinkedHashSet>(
+ Set> exepcted = new LinkedHashSet<>(
Arrays.asList(expectedElementsToBeRemoved));
Collection elementsToRemove = remove.getElementsToRemove();
assertEquals(exepcted.size(), elementsToRemove.size());
From 1815cfc77058e4759a511b3ac80625dde01f904d Mon Sep 17 00:00:00 2001
From: Remi Schnekenburger
Date: Thu, 11 Oct 2018 17:11:50 +0200
Subject: [PATCH 3/9] Issue_253 - Nested executions
- update the nudging policy to be similar to the current implementation
of standard executions
- 2 issues in the tests: 1 is ignored (but not by my dev env) as the
test is not implemented yet, and one that can be reproduced by hand: if
a lifeline has an execution with a nested execution, it can not be
deleted.
Change-Id: I4b52b6d0a7248dcfe01365c40d559602d30406c5
Signed-off-by: Remi Schnekenburger
---
.../InsertNestedExecutionCommand.java | 108 ++++++++++++++----
1 file changed, 88 insertions(+), 20 deletions(-)
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java
index fc77cb4d..833dcef8 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/InsertNestedExecutionCommand.java
@@ -12,9 +12,9 @@
package org.eclipse.papyrus.uml.interaction.internal.model.commands;
+import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
-import java.util.function.Function;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.UnexecutableCommand;
@@ -28,7 +28,9 @@
import org.eclipse.papyrus.uml.interaction.model.MElement;
import org.eclipse.papyrus.uml.interaction.model.MExecution;
import org.eclipse.papyrus.uml.interaction.model.spi.DeferredAddCommand;
+import org.eclipse.papyrus.uml.interaction.model.spi.LayoutConstraints.RelativePosition;
import org.eclipse.papyrus.uml.interaction.model.spi.SemanticHelper;
+import org.eclipse.papyrus.uml.interaction.model.spi.ViewTypes;
import org.eclipse.uml2.uml.Action;
import org.eclipse.uml2.uml.Behavior;
import org.eclipse.uml2.uml.Element;
@@ -133,31 +135,26 @@ protected Command createCommand() {
OptionalInt referenceY;
if (before instanceof MExecution && before == getTarget()) {
- referenceY = OptionalInt.of(0);
+ referenceY = getTarget().getTop();
} else { // before should be an element on the execution itself.
- referenceY = OptionalInt.of(
- layoutHelper().getBottom(reference).getAsInt() - layoutHelper().getTop(getTargetView()));
+ referenceY = OptionalInt.of(layoutHelper().getBottom(reference).getAsInt());
}
if (!referenceY.isPresent()) {
return UnexecutableCommand.INSTANCE;
}
- MElement extends Element> insertionPoint = normalizeFragmentInsertionPoint(before);
- Function paramsFactory = CreationParameters::after;
+ List> timeline = getTimeline(getTarget().getInteraction());
+ int absoluteExecY = referenceY.getAsInt() + offset;
- if (insertionPoint == getTarget()) {
- // Insert before the first covering fragment, if any
- Optional> covering = Optional.of(((MExecution)insertionPoint));
- if (covering.isPresent()) {
- insertionPoint = covering.get();
- paramsFactory = CreationParameters::after;
- }
- }
+ Optional> insertAt = getInsertionPoint(timeline, MExecution.class,
+ absoluteExecY).map(this::normalizeFragmentInsertionPoint);
SemanticHelper semantics = semanticHelper();
- CreationParameters execParams = paramsFactory.apply(insertionPoint.getElement());
+ CreationParameters execParams = CreationParameters.in(getTarget().getInteraction().getElement(),
+ UMLPackage.Literals.INTERACTION__FRAGMENT);
execParams.setEClass(eClass);
+ execParams.setInsertBefore(insertAt.get().getElement());
resultCommand = semantics.createExecutionSpecification(specification, execParams);
CreationParameters startParams = CreationParameters.before(resultCommand);
CreationCommand start = semantics.createStart(resultCommand, startParams);
@@ -171,15 +168,16 @@ protected Command createCommand() {
result = result.chain(new DeferredAddCommand(getTarget().getOwner().getElement(),
UMLPackage.Literals.LIFELINE__COVERED_BY, start, resultCommand, finish));
+ // Make sure we keep enough distance to the element before us
+ int additionalOffset = getAdditionalOffset(timeline, insertAt, absoluteExecY);
+
result = result.chain(diagramHelper().createNestedExecutionShape(resultCommand, getTargetView(),
- referenceY.getAsInt() + offset, height));
+ absoluteExecY - getTarget().getTop().getAsInt(), height));
// Now we have commands to add the execution specification. But, first we must make
// room for it in the diagram. Nudge the element that will follow the new execution
- int spaceAdded = offset + height;
- Optional makeSpace = getTarget().getOwner().following(insertionPoint).map(el -> {
- return el.nudge(spaceAdded);
- });
+ Optional makeSpace = insertAt.flatMap(
+ insertionPoint -> createNudgeCommand(insertionPoint, absoluteExecY + additionalOffset));
if (makeSpace.isPresent()) {
result = makeSpace.get().chain(result);
}
@@ -197,4 +195,74 @@ protected Shape getTargetView() {
View executionView = getTarget().getDiagramView().get();
return Shape.class.cast(executionView);
}
+
+ /**
+ * Creates the nudge command for the insertion of the execution.
+ *
+ * If the insertion of the execution isInsertBefore, the insertionPoint also
+ * needs to be nudged, otherwise we need to nudge everything after the insertion point.
+ *
+ *
+ * @param insertionPoint
+ * the insertion point of the execution's insert command.
+ * @param insertionYPosition
+ * @param additionalOffset
+ * @return the nudge command.
+ */
+ protected Optional createNudgeCommand(MElement extends Element> insertionPoint,
+ int insertionYPosition) {
+ Optional diagramView = getDiagramView(insertionPoint);
+ if (!diagramView.isPresent()) {
+ return Optional.of(insertionPoint.nudge(height));
+ }
+ int curPadding = insertionPoint.getTop().orElse(0) - insertionYPosition;
+ int reqPadding = layoutHelper().getConstraints().getPadding(RelativePosition.BOTTOM,
+ ViewTypes.EXECUTION_SPECIFICATION)
+ + layoutHelper().getConstraints().getPadding(RelativePosition.TOP, diagramView.get());
+ if (curPadding < reqPadding) {
+ return Optional.of(insertionPoint.nudge(height + (reqPadding - curPadding)));
+ } else {
+ return Optional.of(insertionPoint.nudge(height));
+ }
+ }
+
+ private int getAdditionalOffset(List> timeline,
+ Optional> elementAfterMe, int insertionY) {
+ MElement extends Element> elementBeforeMe = getElementBeforeMe(timeline, elementAfterMe);
+ Optional diagramView = getDiagramView(elementBeforeMe);
+ if (!diagramView.isPresent()) {
+ return 0;
+ }
+
+ int curPadding;
+ if (elementBeforeMe == getTarget()) {
+ curPadding = insertionY - elementBeforeMe.getTop().orElse(0); // should be similar to offset
+ } else {
+ curPadding = insertionY - elementBeforeMe.getBottom().orElse(0);
+ }
+
+ int reqPadding = layoutHelper().getConstraints().getPadding(RelativePosition.BOTTOM,
+ diagramView.get())
+ + layoutHelper().getConstraints().getPadding(RelativePosition.TOP,
+ ViewTypes.EXECUTION_SPECIFICATION);
+ if (curPadding < reqPadding) {
+ return reqPadding - curPadding;
+ } else {
+ return 0;
+ }
+ }
+
+ private MElement extends Element> getElementBeforeMe(List> timeline,
+ Optional> elementAfterMe) {
+ if (!elementAfterMe.isPresent()) {
+ return before;
+ }
+
+ int index = timeline.indexOf(elementAfterMe.get()) - 1;
+ if (index >= 0 && index < timeline.size()) {
+ return timeline.get(index);
+ }
+ return before;
+ }
+
}
From eafba7157ff862e7191ed98737d25cc84b560492 Mon Sep 17 00:00:00 2001
From: Remi Schnekenburger
Date: Fri, 12 Oct 2018 14:55:53 +0200
Subject: [PATCH 4/9] issue_253 (nested execution specification)
- update lifeline API with a method to get first level executions to be
able to remove only these executions. Nested ones will be remove in
chain by the remove execution command
- update tests
Change-Id: Iae629bd73730a75880ecdb4ff263aaefd7428ac7
Signed-off-by: Remi Schnekenburger
---
.../model/seqd.ecore | 13 ++++
.../model/seqd.genmodel | 2 +
.../model/SequenceDiagramPackage.java | 59 +++++++++++++++++-
.../internal/model/impl/MExecutionImpl.java | 19 +-----
.../internal/model/impl/MLifelineImpl.java | 60 ++++++++++++++++++
.../impl/SequenceDiagramPackageImpl.java | 32 ++++++++++
.../uml/interaction/model/MLifeline.java | 19 ++++++
.../model/commands/RemoveLifelineCommand.java | 18 +++++-
.../interaction/model/spi/DiagramHelper.java | 2 +-
.../model/tests/MExecutionTest.java | 23 +++++--
.../model/tests/MLifelineTest.java | 62 +++++++++++++++++++
11 files changed, 282 insertions(+), 27 deletions(-)
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore b/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore
index c4d33bfc..baa56d7c 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/model/seqd.ecore
@@ -414,6 +414,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java
index 24b04cae..17e021e5 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/SequenceDiagramPackage.java
@@ -663,6 +663,24 @@ public interface SequenceDiagramPackage extends EPackage {
*/
int MLIFELINE___NUDGE_HORIZONTALLY__INT = MELEMENT_OPERATION_COUNT + 14;
+ /**
+ * The operation id for the 'Get First Level Executions' operation.
+ *
+ * @generated
+ * @ordered
+ */
+ int MLIFELINE___GET_FIRST_LEVEL_EXECUTIONS = MELEMENT_OPERATION_COUNT + 15;
+
+ /**
+ * The operation id for the 'Get Occurrence Specifications' operation.
+ *
+ *
+ * @generated
+ * @ordered
+ */
+ int MLIFELINE___GET_OCCURRENCE_SPECIFICATIONS = MELEMENT_OPERATION_COUNT + 16;
+
/**
* The number of operations of the 'MLifeline' class.
@@ -670,7 +688,7 @@ public interface SequenceDiagramPackage extends EPackage {
* @generated
* @ordered
*/
- int MLIFELINE_OPERATION_COUNT = MELEMENT_OPERATION_COUNT + 15;
+ int MLIFELINE_OPERATION_COUNT = MELEMENT_OPERATION_COUNT + 17;
/**
* The meta object id for the
@@ -2304,6 +2322,28 @@ public interface SequenceDiagramPackage extends EPackage {
*/
EOperation getMLifeline__NudgeHorizontally__int();
+ /**
+ * Returns the meta object for the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MLifeline#getFirstLevelExecutions() Get First
+ * Level Executions}' operation.
+ *
+ * @return the meta object for the 'Get First Level Executions' operation.
+ * @see org.eclipse.papyrus.uml.interaction.model.MLifeline#getFirstLevelExecutions()
+ * @generated
+ */
+ EOperation getMLifeline__GetFirstLevelExecutions();
+
+ /**
+ * Returns the meta object for the
+ * '{@link org.eclipse.papyrus.uml.interaction.model.MLifeline#getOccurrenceSpecifications() Get
+ * Occurrence Specifications}' operation.
+ *
+ * @return the meta object for the 'Get Occurrence Specifications' operation.
+ * @see org.eclipse.papyrus.uml.interaction.model.MLifeline#getOccurrenceSpecifications()
+ * @generated
+ */
+ EOperation getMLifeline__GetOccurrenceSpecifications();
+
/**
* Returns the meta object for class '{@link org.eclipse.papyrus.uml.interaction.model.MExecution
* MExecution}'.
@@ -3163,6 +3203,23 @@ interface Literals {
*/
EOperation MLIFELINE___NUDGE_HORIZONTALLY__INT = eINSTANCE.getMLifeline__NudgeHorizontally__int();
+ /**
+ * The meta object literal for the 'Get First Level Executions' operation.
+ *
+ * @generated
+ */
+ EOperation MLIFELINE___GET_FIRST_LEVEL_EXECUTIONS = eINSTANCE.getMLifeline__GetFirstLevelExecutions();
+
+ /**
+ * The meta object literal for the 'Get Occurrence Specifications' operation.
+ *
+ * @generated
+ */
+ EOperation MLIFELINE___GET_OCCURRENCE_SPECIFICATIONS = eINSTANCE
+ .getMLifeline__GetOccurrenceSpecifications();
+
/**
* The meta object literal for the
* '{@link org.eclipse.papyrus.uml.interaction.internal.model.impl.MExecutionImpl
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java
index 6ebb429b..79389688 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MExecutionImpl.java
@@ -20,7 +20,6 @@
import java.util.Optional;
import java.util.Stack;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.EList;
@@ -36,7 +35,6 @@
import org.eclipse.papyrus.uml.interaction.model.MOccurrence;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ExecutionSpecification;
-import org.eclipse.uml2.uml.OccurrenceSpecification;
/**
* An implementation of the model object 'MExecution'.
*
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java
index 6eedfb7a..19ded4aa 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/MLifelineImpl.java
@@ -15,10 +15,13 @@
import static org.eclipse.papyrus.uml.interaction.graph.GraphPredicates.covers;
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
+import java.util.Stack;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.Notification;
@@ -44,6 +47,7 @@
import org.eclipse.papyrus.uml.interaction.model.MExecutionOccurrence;
import org.eclipse.papyrus.uml.interaction.model.MInteraction;
import org.eclipse.papyrus.uml.interaction.model.MLifeline;
+import org.eclipse.papyrus.uml.interaction.model.MOccurrence;
import org.eclipse.papyrus.uml.interaction.model.spi.ExecutionCreationCommandParameter;
import org.eclipse.uml2.uml.DestructionOccurrenceSpecification;
import org.eclipse.uml2.uml.Element;
@@ -53,6 +57,7 @@
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageSort;
import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.OccurrenceSpecification;
/**
* An implementation of the model object 'MLifeline'.
+ *
+ * @generated NOT
+ */
+ @Override
+ public List getFirstLevelExecutions() {
+ List nestedExecutions = new ArrayList<>();
+ // browse all executions on this lifeline and check the virtual owner
+ List> occurrences = getOccurrenceSpecifications();
+
+ Stack stack = new Stack<>();
+ for (MOccurrence> occurence : occurrences) {
+ // check if it starts a new occurrence. If yes, adds it on top of the stack
+ // if it finishes, removes the finished execution from the stack
+ occurence.getFinishedExecution().ifPresent(__ -> {
+ if (!stack.isEmpty()) {
+ stack.pop();
+ }
+ });
+ if (occurence.getStartedExecution().isPresent()) {
+ MExecution execution = occurence.getStartedExecution().get();
+ // if current owner is null, that mean that the direct owner is the lifeline, so it should be
+ // added in the list
+ if (stack.empty()) {
+ nestedExecutions.add(execution);
+ }
+ stack.push(execution);
+ }
+ }
+ return nestedExecutions;
+
+ }
+
+ /**
+ *
+ *
+ * @generated NOT
+ */
+ @Override
+ public List> getOccurrenceSpecifications() {
+ List> orderedCoveredBys = getInteraction().getElement().getFragments().stream()
+ .filter(frg -> frg.getCovereds().contains(getElement())) //
+ .filter(OccurrenceSpecification.class::isInstance) //
+ .map(el -> getInteraction().getElement(el)) //
+ .filter(e -> e.isPresent()) //
+ .map(e -> MOccurrence.class.cast(e.get())) //
+ .collect(Collectors.toList());
+ return orderedCoveredBys;
+ }
+
/**
*
*
@@ -595,6 +651,10 @@ public Object eInvoke(int operationID, EList> arguments) throws InvocationTarg
return elementAt((Integer)arguments.get(0));
case SequenceDiagramPackage.MLIFELINE___NUDGE_HORIZONTALLY__INT:
return nudgeHorizontally((Integer)arguments.get(0));
+ case SequenceDiagramPackage.MLIFELINE___GET_FIRST_LEVEL_EXECUTIONS:
+ return getFirstLevelExecutions();
+ case SequenceDiagramPackage.MLIFELINE___GET_OCCURRENCE_SPECIFICATIONS:
+ return getOccurrenceSpecifications();
}
return super.eInvoke(operationID, arguments);
}
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java
index 3e952910..c9e4d95a 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/internal/model/impl/SequenceDiagramPackageImpl.java
@@ -666,6 +666,26 @@ public EOperation getMLifeline__NudgeHorizontally__int() {
return mLifelineEClass.getEOperations().get(14);
}
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getMLifeline__GetFirstLevelExecutions() {
+ return mLifelineEClass.getEOperations().get(15);
+ }
+
+ /**
+ *
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getMLifeline__GetOccurrenceSpecifications() {
+ return mLifelineEClass.getEOperations().get(16);
+ }
+
/**
*
*
@@ -1157,6 +1177,8 @@ public void createPackageContents() {
MLIFELINE___INSERT_MESSAGE_AFTER__MELEMENT_INT_MLIFELINE_MESSAGESORT_NAMEDELEMENT_EXECUTIONCREATIONCOMMANDPARAMETER);
createEOperation(mLifelineEClass, MLIFELINE___ELEMENT_AT__INT);
createEOperation(mLifelineEClass, MLIFELINE___NUDGE_HORIZONTALLY__INT);
+ createEOperation(mLifelineEClass, MLIFELINE___GET_FIRST_LEVEL_EXECUTIONS);
+ createEOperation(mLifelineEClass, MLIFELINE___GET_OCCURRENCE_SPECIFICATIONS);
mExecutionEClass = createEClass(MEXECUTION);
createEAttribute(mExecutionEClass, MEXECUTION__START);
@@ -1640,6 +1662,16 @@ public void initializePackageContents() {
1, IS_UNIQUE, IS_ORDERED);
addEParameter(op, ecorePackage.getEInt(), "deltaX", 1, 1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+ initEOperation(getMLifeline__GetFirstLevelExecutions(), this.getMExecution(),
+ "getFirstLevelExecutions", 0, -1, IS_UNIQUE, IS_ORDERED); //$NON-NLS-1$
+
+ op = initEOperation(getMLifeline__GetOccurrenceSpecifications(), null, "getOccurrenceSpecifications", //$NON-NLS-1$
+ 0, -1, IS_UNIQUE, IS_ORDERED);
+ g1 = createEGenericType(this.getMOccurrence());
+ g2 = createEGenericType();
+ g1.getETypeArguments().add(g2);
+ initEOperation(op, g1);
+
initEClass(mExecutionEClass, MExecution.class, "MExecution", !IS_ABSTRACT, !IS_INTERFACE, //$NON-NLS-1$
IS_GENERATED_INSTANCE_CLASS);
g1 = createEGenericType(this.getOptional());
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MLifeline.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MLifeline.java
index 7bdd2682..a90dae46 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MLifeline.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src-gen/org/eclipse/papyrus/uml/interaction/model/MLifeline.java
@@ -364,4 +364,23 @@ CreationCommand insertMessageAfter(MElement> before, int offset, MLif
*/
Command nudgeHorizontally(int deltaX);
+ /**
+ * Query the list of owned
+ * {@link MExecution} that are directly on the lifeline, and not virtual children of another execution of
+ * this lifeline.
+ *
+ * @model kind="operation"
+ * @generated
+ */
+ List getFirstLevelExecutions();
+
+ /**
+ * Query the {@link MOccurrence} in
+ * timeline order that are on this lifeline
+ *
+ * @model kind="operation"
+ * @generated
+ */
+ List> getOccurrenceSpecifications();
+
} // MLifeline
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveLifelineCommand.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveLifelineCommand.java
index 4e4706ec..94b38ee3 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveLifelineCommand.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/internal/model/commands/RemoveLifelineCommand.java
@@ -17,6 +17,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.eclipse.emf.common.command.Command;
@@ -24,6 +25,7 @@
import org.eclipse.papyrus.uml.interaction.internal.model.impl.MInteractionImpl;
import org.eclipse.papyrus.uml.interaction.internal.model.impl.MLifelineImpl;
import org.eclipse.papyrus.uml.interaction.internal.model.impl.MMessageImpl;
+import org.eclipse.papyrus.uml.interaction.model.MExecution;
import org.eclipse.papyrus.uml.interaction.model.spi.DiagramHelper;
import org.eclipse.papyrus.uml.interaction.model.spi.ElementRemovalCommandImpl;
import org.eclipse.papyrus.uml.interaction.model.spi.RemovalCommand;
@@ -61,14 +63,15 @@ protected Command createCommand() {
List> removalCommands = new ArrayList<>(lifeline.getExecutions().size() + 1);
/* collect non execution related messages */
- Set messageEndsToDelete = new LinkedHashSet(
+ Set messageEndsToDelete = new LinkedHashSet<>(
lifeline.getElement().getCoveredBys().stream()//
.filter(MessageOccurrenceSpecification.class::isInstance)//
.map(MessageOccurrenceSpecification.class::cast)//
.collect(Collectors.toSet()));
- /* remove executions */
- lifeline.getExecutions().forEach(e -> {
+ /* remove executions (only first level, others will be removed by dependency */
+
+ lifeline.getFirstLevelExecutions().forEach(e -> {
e.getStart().ifPresent(o -> messageEndsToDelete.remove(o.getElement()));
e.getFinish().ifPresent(o -> messageEndsToDelete.remove(o.getElement()));
removalCommands.add(new RemoveExecutionCommand((MExecutionImpl)e, false));
@@ -115,4 +118,13 @@ public Collection getElementsToRemove() {
return delegate.getElementsToRemove();
}
+ public static class IsDirectlyNested implements Predicate {
+
+ @Override
+ public boolean test(MExecution t) {
+ return false;
+ }
+
+ }
+
}
diff --git a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java
index 332ff252..65d64db2 100644
--- a/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java
+++ b/plugins/org.eclipse.papyrus.uml.interaction.model/src/org/eclipse/papyrus/uml/interaction/model/spi/DiagramHelper.java
@@ -102,7 +102,7 @@ CreationCommand createLifelineShape(Supplier extends Lifeline> lifeline
CreationCommand createExecutionShape(Supplier extends ExecutionSpecification> execution,
Shape lifeline, int yPosition, int height);
-/**
+ /**
* Obtain a command to create a shape for the given {@code execution} specification as a child of another
* {@link ExecutionSpecification} shape in the diagram.
*
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
index 81cf0e0f..95b3201a 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MExecutionTest.java
@@ -28,8 +28,9 @@
import org.eclipse.papyrus.uml.interaction.model.MExecution;
import org.eclipse.uml2.uml.ActionExecutionSpecification;
import org.eclipse.uml2.uml.ExecutionSpecification;
+import org.eclipse.uml2.uml.OpaqueAction;
+import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
-import org.junit.Ignore;
import junit.textui.TestRunner;
@@ -206,13 +207,23 @@ public void testGetDiagramView() {
*
* @see org.eclipse.papyrus.uml.interaction.model.MExecution#insertNestedExecutionAfter(org.eclipse.papyrus.uml.interaction.model.MElement,
* int, int, org.eclipse.uml2.uml.Element)
- * @generated
+ * @generated NOT
*/
- @Ignore
public void testInsertNestedExecutionAfter__MElement_int_int_Element() {
- // TODO: implement this operation test method
- // Ensure that you remove @generated or mark it @generated NOT
- fail();
+ OpaqueAction action = UMLFactory.eINSTANCE.createOpaqueAction();
+ assertThat(getFixture().getNestedExecutions().size(), equalTo(1));
+ CreationCommand command = getFixture()
+ .insertNestedExecutionAfter(getFixture(), 12, 22, action);
+
+ assertThat(command, executable());
+ ExecutionSpecification execSpec = create(command);
+ MExecution exec = getFixture().getOwner().getExecution(execSpec).get();
+ assertThat(exec.getOwner(), is(getFixture().getOwner()));
+ assertThat(exec.getTop().getAsInt(), is(104)); // top of the nesting exec: 92, +offset: 12
+ assertThat(exec.getBottom().getAsInt(), is(126)); // length = 22
+ assertThat(exec.getElement(), instanceOf(ActionExecutionSpecification.class));
+ assertThat(((ActionExecutionSpecification)exec.getElement()).getAction(), is(action));
+ assertThat(getFixture().getNestedExecutions().size(), equalTo(2));
}
/**
diff --git a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
index 8f71d651..1226fb1e 100644
--- a/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
+++ b/tests/org.eclipse.papyrus.uml.interaction.model.tests/src-gen/org/eclipse/papyrus/uml/interaction/model/tests/MLifelineTest.java
@@ -21,6 +21,7 @@
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
+import java.util.List;
import java.util.Optional;
import org.eclipse.emf.common.command.Command;
@@ -44,6 +45,7 @@
import org.eclipse.uml2.uml.MessageEnd;
import org.eclipse.uml2.uml.MessageKind;
import org.eclipse.uml2.uml.MessageSort;
+import org.eclipse.uml2.uml.OccurrenceSpecification;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.UMLPackage;
import org.junit.Assume;
@@ -91,6 +93,10 @@
*
{@link org.eclipse.papyrus.uml.interaction.model.MLifeline#elementAt(int) Element At}