aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCamille Letavernier2018-05-25 03:54:19 -0400
committerNicolas FAUVERGUE2018-06-08 04:24:35 -0400
commita523a1589c4725f5ecb77ecd28f52520894da43e (patch)
treeadad19a34f8864ca10a495f3c8692b5942a789a8
parent4bcc40a183aa9f2a4131f884e20041c732ef9227 (diff)
downloadorg.eclipse.papyrus-a523a1589c4725f5ecb77ecd28f52520894da43e.tar.gz
org.eclipse.papyrus-a523a1589c4725f5ecb77ecd28f52520894da43e.tar.xz
org.eclipse.papyrus-a523a1589c4725f5ecb77ecd28f52520894da43e.zip
Bug 535097: [Sequence Diagram] Semantic coverage of Operands must be
consistent with visuals https://bugs.eclipse.org/bugs/show_bug.cgi?id=535097 Signed-off-by: Camille Letavernier <cletavernier@eclipsesource.com> Change-Id: I3d97ee1819eb3f374a3d4b2de3644d78f11469d1
-rw-r--r--plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java11
-rw-r--r--plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedFragmentResizeEditPolicy.java41
-rw-r--r--plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ConnectRectangleToGridEditPolicy.java16
-rw-r--r--plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java2
-rw-r--r--tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.di2
-rw-r--r--tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.notation108
-rw-r--r--tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.uml31
-rw-r--r--tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/BugTests.java1
-rw-r--r--tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/TestCFOperandsSemanticCoverage.java482
9 files changed, 667 insertions, 27 deletions
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java
index 25c0fab4fb9..f130979a26b 100644
--- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java
+++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedCreationEditPolicy.java
@@ -136,8 +136,10 @@ public class CombinedCreationEditPolicy extends DefaultCreationEditPolicy {
// We get the size from the mouse cursor location to the bottom of the existing operand
int height = targetOperandBounds.getBottom().y() - locationToOperand.y();
+ int width = compartmentFigure.getBounds().width();
+
int distanceToCompartmentTop = compartmentFigure.getBounds().getTopLeft().getNegated().translate(locationToCompartment).y;
- Rectangle bounds = new Rectangle(0, distanceToCompartmentTop, -1, height);
+ Rectangle bounds = new Rectangle(0, distanceToCompartmentTop, width, height);
ICommand setBoundsCommand = new SetResizeAndLocationCommand(editingDomain, "Set dimension", descriptor, bounds);
// Also reduce the size of the existing operand, to avoid shifting the entire operands stack
@@ -145,16 +147,15 @@ public class CombinedCreationEditPolicy extends DefaultCreationEditPolicy {
int siblingHeight = targetOperandPart.getFigure().getBounds().height();
- Dimension siblingDimension = new Dimension(-1, siblingHeight - height);
+ Dimension siblingDimension = new Dimension(width, siblingHeight - height);
ICommand reduceSiblingSizeCommand = new SetResizeCommand(editingDomain, "Set dimension", new NotationAndTypeAdapter(view.getElement(), view), siblingDimension);
return setBoundsCommand.compose(reduceSiblingSizeCommand);
}
// Shouldn't happen in a well-formed diagram, since a CF should always have at least one operand.
- // If this happens, simply take all available height
+ // If this happens, simply take all available size
Rectangle clientArea = compartmentFigure.getClientArea();
- int height = clientArea.height();
- Dimension size = new Dimension(-1, height);
+ Dimension size = new Dimension(clientArea.getSize());
ICommand setBoundsCommand = new SetResizeCommand(editingDomain, "Set dimension", descriptor, size);
return setBoundsCommand;
}
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedFragmentResizeEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedFragmentResizeEditPolicy.java
index f2481a6d22c..cf7b16985c6 100644
--- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedFragmentResizeEditPolicy.java
+++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/edit/policies/CombinedFragmentResizeEditPolicy.java
@@ -139,31 +139,38 @@ public class CombinedFragmentResizeEditPolicy extends ResizableEditPolicyEx {
int direction = cbr.getResizeDirection();
List<GraphicalEditPart> operands = getOperands();
- if (!operands.isEmpty() && ((direction & PositionConstants.NORTH) != 0 || (direction & PositionConstants.SOUTH) != 0)) {
- ChangeBoundsRequest resizeFirstOrLastOperand = new ChangeBoundsRequest();
+ if (!operands.isEmpty()) {
+ ChangeBoundsRequest resizeOperand = new ChangeBoundsRequest();
GraphicalEditPart operand;
+ int firstOrLastOperandResizeDirection;
if ((direction & PositionConstants.NORTH) != 0) {
operand = operands.get(0);
- resizeFirstOrLastOperand.setResizeDirection(PositionConstants.NORTH);
+ firstOrLastOperandResizeDirection = PositionConstants.NORTH;
} else {
operand = operands.get(operands.size() - 1);
- resizeFirstOrLastOperand.setResizeDirection(PositionConstants.SOUTH);
+ firstOrLastOperandResizeDirection = PositionConstants.SOUTH;
}
- resizeFirstOrLastOperand.setMoveDelta(cbr.getMoveDelta());
- resizeFirstOrLastOperand.setLocation(cbr.getLocation());
- resizeFirstOrLastOperand.setEditParts(operand);
- resizeFirstOrLastOperand.setSizeDelta(new Dimension(0, cbr.getSizeDelta().height));
- resizeFirstOrLastOperand.setType(RequestConstants.REQ_RESIZE);
- commands.add(operand.getCommand(resizeFirstOrLastOperand));
- } else {
- // Width change only; nothing is required.
- // XXX Optionally, we may force the new width to all operands. That's not required, as the layout
- // will take care of that anyway.
- return resizeCFCommand;
- }
+ resizeOperand.setMoveDelta(cbr.getMoveDelta());
+ resizeOperand.setLocation(cbr.getLocation());
+ resizeOperand.setType(RequestConstants.REQ_RESIZE);
+
+ for (GraphicalEditPart operandPart : operands) {
+ resizeOperand.setEditParts(operand);
+ if (operandPart == operand) {
+ // Give all the delta (Height and width) to either the first or last operand
+ resizeOperand.setSizeDelta(new Dimension(cbr.getSizeDelta()));
+ resizeOperand.setResizeDirection(firstOrLastOperandResizeDirection);
+ } else {
+ // Give only the width delta to other operands
+ resizeOperand.setSizeDelta(new Dimension(cbr.getSizeDelta().width(), 0));
+ resizeOperand.setResizeDirection(PositionConstants.EAST);
+ }
+ commands.add(operandPart.getCommand(resizeOperand));
+ }
- return command;
+ return command;
+ }
}
return resizeCFCommand;
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ConnectRectangleToGridEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ConnectRectangleToGridEditPolicy.java
index 1b5f4154fb1..bba8bc51415 100644
--- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ConnectRectangleToGridEditPolicy.java
+++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ConnectRectangleToGridEditPolicy.java
@@ -365,6 +365,10 @@ public class ConnectRectangleToGridEditPolicy extends ConnectToGridEditPolicy im
protected void updateColumnStartFromXNotification(PrecisionRectangle bounds) {
int newX = bounds.x();
updatePositionGridAxis(columnStart, newX, 0);
+ if (columnFinish != null) {
+ newX = bounds.x() + bounds.width();
+ updatePositionGridAxis(columnFinish, newX, 0);
+ }
UMLDiagramEditorPlugin.log.trace(LogOptions.SEQUENCE_DEBUG_REFERENCEGRID, "+---->ACTION: modifiy AXIS START to x=" + newX);//$NON-NLS-1$
}
@@ -402,10 +406,14 @@ public class ConnectRectangleToGridEditPolicy extends ConnectToGridEditPolicy im
/**
* This allows to update the position of anchor after the move.
*
- * @param anchor The anchor to recalculate.
- * @param node The moved node.
- * @param oldY The old Y position.
- * @param newY The new Y position.
+ * @param anchor
+ * The anchor to recalculate.
+ * @param node
+ * The moved node.
+ * @param oldY
+ * The old Y position.
+ * @param newY
+ * The new Y position.
*/
protected void updateAnchorFromY(IdentityAnchor anchor, Node node, int oldY, int newY) {
if (null != anchor && !anchor.getId().trim().equals("")) { //$NON-NLS-1$
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java
index 8a87ae6ea46..7f4cf8f0054 100644
--- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java
+++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence/custom-src/org/eclipse/papyrus/uml/diagram/sequence/referencialgrilling/ResizeOperandEditPolicy.java
@@ -124,7 +124,7 @@ public class ResizeOperandEditPolicy extends GraphicalEditPolicy {
operandFigure.translateToRelative(bounds);
// Set the new bounds, relative to the parent (CombinedFragment), to make
- // sure the notation is consistent with the visuals. We should get x = 0; y = sizeOf(Cf_Label) + Sum(sizeOf(previousOperands))
+ // sure the notation is consistent with the visuals. We should get x = 0; y = Sum(sizeOf(previousOperands)); width = width(CF)
IFigure cfFigure = ((IGraphicalEditPart) operandPart.getParent()).getFigure();
bounds.translate(cfFigure.getBounds().getTopLeft().getNegated());
diff --git a/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.di b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.di
new file mode 100644
index 00000000000..8c549eecdc6
--- /dev/null
+++ b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.di
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<architecture:ArchitectureDescription xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:architecture="http://www.eclipse.org/papyrus/infra/core/architecture" contextId="org.eclipse.papyrus.infra.services.edit.TypeContext"/>
diff --git a/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.notation b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.notation
new file mode 100644
index 00000000000..0d9d5c5c8b2
--- /dev/null
+++ b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.notation
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:css="http://www.eclipse.org/papyrus/infra/gmfdiag/css" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.2/notation" xmlns:style="http://www.eclipse.org/papyrus/infra/gmfdiag/style" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML">
+ <notation:Diagram xmi:id="_3YCFEF_vEei3wLtnYCLwnw" type="PapyrusUMLSequenceDiagram" name="SemanticCoverageTest" measurementUnit="Pixel">
+ <children xmi:type="notation:Shape" xmi:id="_3YCFEV_vEei3wLtnYCLwnw" type="Interaction_Shape">
+ <children xmi:type="notation:DecorationNode" xmi:id="_3YCFEl_vEei3wLtnYCLwnw" type="Interaction_NameLabel"/>
+ <children xmi:type="notation:BasicCompartment" xmi:id="_3YCFE1_vEei3wLtnYCLwnw" type="Interaction_SubfragmentCompartment">
+ <children xmi:type="notation:Shape" xmi:id="_bykvgF_wEei3wLtnYCLwnw" type="CombinedFragment_Shape">
+ <children xmi:type="notation:BasicCompartment" xmi:id="_bykvgl_wEei3wLtnYCLwnw" type="CombinedFragment_SubfragmentCompartment">
+ <children xmi:type="notation:Shape" xmi:id="_bylWkF_wEei3wLtnYCLwnw" type="InteractionOperand_Shape">
+ <children xmi:type="notation:DecorationNode" xmi:id="_bylWkl_wEei3wLtnYCLwnw" type="InteractionOperand_Guard">
+ <element xmi:type="uml:InteractionConstraint" href="bug535097-OperandsSemantic.uml#_byZwYF_wEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_bylWk1_wEei3wLtnYCLwnw" x="5" y="5"/>
+ </children>
+ <element xmi:type="uml:InteractionOperand" href="bug535097-OperandsSemantic.uml#_byZJUF_wEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_bylWkV_wEei3wLtnYCLwnw" width="401" height="182"/>
+ </children>
+ <styles xmi:type="notation:SortingStyle" xmi:id="_bykvg1_wEei3wLtnYCLwnw"/>
+ <styles xmi:type="notation:FilteringStyle" xmi:id="_bykvhF_wEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_bykvhV_wEei3wLtnYCLwnw"/>
+ </children>
+ <element xmi:type="uml:CombinedFragment" href="bug535097-OperandsSemantic.uml#_byQmcF_wEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_bykvgV_wEei3wLtnYCLwnw" x="74" y="96" width="401" height="201"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_5ndxEF_vEei3wLtnYCLwnw" type="Lifeline_Shape">
+ <children xmi:type="notation:DecorationNode" xmi:id="_5neYIF_vEei3wLtnYCLwnw" type="Lifeline_NameLabel"/>
+ <children xmi:type="notation:Shape" xmi:id="_qK4DEF_2EeiussJ5A9xGlQ" type="ActionExecutionSpecification_Shape">
+ <element xmi:type="uml:ActionExecutionSpecification" href="bug535097-OperandsSemantic.uml#_qKqAoF_2EeiussJ5A9xGlQ"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_qK4DEV_2EeiussJ5A9xGlQ" x="40" y="146" width="20" height="100"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_ti9ZMF_2EeiussJ5A9xGlQ" type="ActionExecutionSpecification_Shape">
+ <element xmi:type="uml:ActionExecutionSpecification" href="bug535097-OperandsSemantic.uml#_tikXoF_2EeiussJ5A9xGlQ"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_ti9ZMV_2EeiussJ5A9xGlQ" x="40" y="326" width="20" height="100"/>
+ </children>
+ <element xmi:type="uml:Lifeline" href="bug535097-OperandsSemantic.uml#_5nUAEF_vEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_5ndxEV_vEei3wLtnYCLwnw" x="114" y="10"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_5vV6sF_vEei3wLtnYCLwnw" type="Lifeline_Shape">
+ <children xmi:type="notation:DecorationNode" xmi:id="_5vWhwF_vEei3wLtnYCLwnw" type="Lifeline_NameLabel"/>
+ <element xmi:type="uml:Lifeline" href="bug535097-OperandsSemantic.uml#_5vRpQF_vEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_5vV6sV_vEei3wLtnYCLwnw" x="314" y="10"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_53MPIF_vEei3wLtnYCLwnw" type="Lifeline_Shape">
+ <children xmi:type="notation:DecorationNode" xmi:id="_53M2MF_vEei3wLtnYCLwnw" type="Lifeline_NameLabel"/>
+ <element xmi:type="uml:Lifeline" href="bug535097-OperandsSemantic.uml#_52-zwF_vEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_53MPIV_vEei3wLtnYCLwnw" x="654" y="10"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_6CNMUF_vEei3wLtnYCLwnw" type="Lifeline_Shape">
+ <children xmi:type="notation:DecorationNode" xmi:id="_6CNMUl_vEei3wLtnYCLwnw" type="Lifeline_NameLabel"/>
+ <element xmi:type="uml:Lifeline" href="bug535097-OperandsSemantic.uml#_6CBmIF_vEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_6CNMUV_vEei3wLtnYCLwnw" x="494" y="10"/>
+ </children>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_3YCFFF_vEei3wLtnYCLwnw"/>
+ </children>
+ <element xmi:type="uml:Interaction" href="bug535097-OperandsSemantic.uml#_3XhHsF_vEei3wLtnYCLwnw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_3YCFFV_vEei3wLtnYCLwnw"/>
+ </children>
+ <styles xmi:type="notation:StringValueStyle" xmi:id="_3YCFFl_vEei3wLtnYCLwnw" name="diagram_compatibility_version" stringValue="1.4.0"/>
+ <styles xmi:type="notation:DiagramStyle" xmi:id="_3YCFF1_vEei3wLtnYCLwnw"/>
+ <styles xmi:type="style:PapyrusDiagramStyle" xmi:id="_3YCFGF_vEei3wLtnYCLwnw" diagramKindId="org.eclipse.papyrus.uml.diagram.sequence">
+ <owner xmi:type="uml:Model" href="bug535097-OperandsSemantic.uml#_3U8U0F_vEei3wLtnYCLwnw"/>
+ </styles>
+ <styles xmi:type="notation:EObjectListValueStyle" xmi:id="_kLDn8F_xEei3wLtnYCLwnw" name="css_stylesheets" eObjectListValue="_kK-IYF_xEei3wLtnYCLwnw"/>
+ <element xmi:type="uml:Interaction" href="bug535097-OperandsSemantic.uml#_3XhHsF_vEei3wLtnYCLwnw"/>
+ <edges xmi:type="notation:Connector" xmi:id="_xGHW4F_2EeiussJ5A9xGlQ" type="Message_AsynchEdge" source="_5ndxEF_vEei3wLtnYCLwnw" target="_5vV6sF_vEei3wLtnYCLwnw">
+ <children xmi:type="notation:DecorationNode" xmi:id="_xGHW41_2EeiussJ5A9xGlQ" type="Message_AsynchNameLabel">
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_xGHW5F_2EeiussJ5A9xGlQ" x="1" y="-13"/>
+ </children>
+ <children xmi:type="notation:DecorationNode" xmi:id="_xGHW5V_2EeiussJ5A9xGlQ" type="Message_AsynchStereotypeLabel">
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_xGHW5l_2EeiussJ5A9xGlQ" x="1" y="-33"/>
+ </children>
+ <styles xmi:type="notation:FontStyle" xmi:id="_xGHW4V_2EeiussJ5A9xGlQ"/>
+ <styles xmi:type="notation:LineStyle" xmi:id="_xGH98F_2EeiussJ5A9xGlQ"/>
+ <element xmi:type="uml:Message" href="bug535097-OperandsSemantic.uml#_xBsJ4F_2EeiussJ5A9xGlQ"/>
+ <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_xGHW4l_2EeiussJ5A9xGlQ" points="[-10, -3, -210, 0]$[200, -3, 0, 0]"/>
+ <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_xGo7UF_2EeiussJ5A9xGlQ" id="(0.5,0.23714285714285716)"/>
+ <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_xGo7UV_2EeiussJ5A9xGlQ" id="(0.5,0.23714285714285716)"/>
+ </edges>
+ <edges xmi:type="notation:Connector" xmi:id="_xaJGIF_2EeiussJ5A9xGlQ" type="Message_AsynchEdge" source="_5vV6sF_vEei3wLtnYCLwnw" target="_5ndxEF_vEei3wLtnYCLwnw">
+ <children xmi:type="notation:DecorationNode" xmi:id="_xaJtMF_2EeiussJ5A9xGlQ" type="Message_AsynchNameLabel">
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_xaJtMV_2EeiussJ5A9xGlQ" x="1" y="-13"/>
+ </children>
+ <children xmi:type="notation:DecorationNode" xmi:id="_xaJtMl_2EeiussJ5A9xGlQ" type="Message_AsynchStereotypeLabel">
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_xaJtM1_2EeiussJ5A9xGlQ" x="1" y="-33"/>
+ </children>
+ <styles xmi:type="notation:FontStyle" xmi:id="_xaJGIV_2EeiussJ5A9xGlQ"/>
+ <styles xmi:type="notation:LineStyle" xmi:id="_xaJtNF_2EeiussJ5A9xGlQ"/>
+ <element xmi:type="uml:Message" href="bug535097-OperandsSemantic.uml#_xZu2cF_2EeiussJ5A9xGlQ"/>
+ <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_xaJGIl_2EeiussJ5A9xGlQ" points="[0, 0, 200, 0]$[-210, 0, -10, 0]"/>
+ <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_xaxYQF_2EeiussJ5A9xGlQ" id="(0.5,0.29428571428571426)"/>
+ <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_xaxYQV_2EeiussJ5A9xGlQ" id="(0.5,0.29428571428571426)"/>
+ </edges>
+ <edges xmi:type="notation:Connector" xmi:id="_yH4V4F_2EeiussJ5A9xGlQ" type="Message_AsynchEdge" source="_5vV6sF_vEei3wLtnYCLwnw" target="_53MPIF_vEei3wLtnYCLwnw">
+ <children xmi:type="notation:DecorationNode" xmi:id="_yH488F_2EeiussJ5A9xGlQ" type="Message_AsynchNameLabel">
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_yH488V_2EeiussJ5A9xGlQ" x="1" y="-13"/>
+ </children>
+ <children xmi:type="notation:DecorationNode" xmi:id="_yH488l_2EeiussJ5A9xGlQ" type="Message_AsynchStereotypeLabel">
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_yH4881_2EeiussJ5A9xGlQ" x="1" y="-33"/>
+ </children>
+ <styles xmi:type="notation:FontStyle" xmi:id="_yH4V4V_2EeiussJ5A9xGlQ"/>
+ <styles xmi:type="notation:LineStyle" xmi:id="_yH489F_2EeiussJ5A9xGlQ"/>
+ <element xmi:type="uml:Message" href="bug535097-OperandsSemantic.uml#_yHfUUF_2EeiussJ5A9xGlQ"/>
+ <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_yH4V4l_2EeiussJ5A9xGlQ" points="[0, 0, -340, 0]$[340, 0, 0, 0]"/>
+ <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_yIYsMF_2EeiussJ5A9xGlQ" id="(0.5,0.4942857142857143)"/>
+ <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_yIYsMV_2EeiussJ5A9xGlQ" id="(0.5,0.4942857142857143)"/>
+ </edges>
+ </notation:Diagram>
+ <css:StyleSheetReference xmi:id="_kK-IYF_xEei3wLtnYCLwnw" path="/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/style.css"/>
+</xmi:XMI>
diff --git a/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.uml b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.uml
new file mode 100644
index 00000000000..9eaac2b1fef
--- /dev/null
+++ b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/resource/bugs/bug535097-OperandsSemantic.uml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_3U8U0F_vEei3wLtnYCLwnw" name="bug535097-OperandsSemantic">
+ <packageImport xmi:type="uml:PackageImport" xmi:id="_3f3LYF_vEei3wLtnYCLwnw">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Interaction" xmi:id="_3XhHsF_vEei3wLtnYCLwnw" name="Interaction1">
+ <lifeline xmi:type="uml:Lifeline" xmi:id="_5nUAEF_vEei3wLtnYCLwnw" name="Lifeline1" coveredBy="_byZJUF_wEei3wLtnYCLwnw _xBxCYF_2EeiussJ5A9xGlQ _xZwEkV_2EeiussJ5A9xGlQ _qKr10V_2EeiussJ5A9xGlQ _qKqAoF_2EeiussJ5A9xGlQ _timM0F_2EeiussJ5A9xGlQ _tikXoF_2EeiussJ5A9xGlQ _timz4F_2EeiussJ5A9xGlQ"/>
+ <lifeline xmi:type="uml:Lifeline" xmi:id="_5vRpQF_vEei3wLtnYCLwnw" name="Lifeline2" coveredBy="_byZJUF_wEei3wLtnYCLwnw _xBxpcF_2EeiussJ5A9xGlQ _xZwEkF_2EeiussJ5A9xGlQ _yHhwkF_2EeiussJ5A9xGlQ"/>
+ <lifeline xmi:type="uml:Lifeline" xmi:id="_52-zwF_vEei3wLtnYCLwnw" name="Lifeline3" coveredBy="_yHi-sF_2EeiussJ5A9xGlQ _byZJUF_wEei3wLtnYCLwnw"/>
+ <lifeline xmi:type="uml:Lifeline" xmi:id="_6CBmIF_vEei3wLtnYCLwnw" name="Lifeline4" coveredBy="_byZJUF_wEei3wLtnYCLwnw"/>
+ <fragment xmi:type="uml:ExecutionOccurrenceSpecification" xmi:id="_timM0F_2EeiussJ5A9xGlQ" name="Exec2Start" covered="_5nUAEF_vEei3wLtnYCLwnw" execution="_tikXoF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:ActionExecutionSpecification" xmi:id="_tikXoF_2EeiussJ5A9xGlQ" name="Exec2" covered="_5nUAEF_vEei3wLtnYCLwnw" finish="_timz4F_2EeiussJ5A9xGlQ" start="_timM0F_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:MessageOccurrenceSpecification" xmi:id="_yHhwkF_2EeiussJ5A9xGlQ" name="Message12SendEvent" covered="_5vRpQF_vEei3wLtnYCLwnw" message="_yHfUUF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:MessageOccurrenceSpecification" xmi:id="_yHi-sF_2EeiussJ5A9xGlQ" name="Message12ReceiveEvent" covered="_52-zwF_vEei3wLtnYCLwnw" message="_yHfUUF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:ExecutionOccurrenceSpecification" xmi:id="_timz4F_2EeiussJ5A9xGlQ" name="Exec2Finish" covered="_5nUAEF_vEei3wLtnYCLwnw" execution="_tikXoF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:ActionExecutionSpecification" xmi:id="_qKqAoF_2EeiussJ5A9xGlQ" name="Exec1" covered="_5nUAEF_vEei3wLtnYCLwnw" finish="_qKr10V_2EeiussJ5A9xGlQ" start="_xBxCYF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:CombinedFragment" xmi:id="_byQmcF_wEei3wLtnYCLwnw" name="TestFragment">
+ <operand xmi:type="uml:InteractionOperand" xmi:id="_byZJUF_wEei3wLtnYCLwnw" name="InteractionOperand0" covered="_5nUAEF_vEei3wLtnYCLwnw _52-zwF_vEei3wLtnYCLwnw _5vRpQF_vEei3wLtnYCLwnw _6CBmIF_vEei3wLtnYCLwnw">
+ <fragment xmi:type="uml:MessageOccurrenceSpecification" xmi:id="_xBxCYF_2EeiussJ5A9xGlQ" name="Message10SendEvent" covered="_5nUAEF_vEei3wLtnYCLwnw" message="_xBsJ4F_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:MessageOccurrenceSpecification" xmi:id="_xBxpcF_2EeiussJ5A9xGlQ" name="Message10ReceiveEvent" covered="_5vRpQF_vEei3wLtnYCLwnw" message="_xBsJ4F_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:MessageOccurrenceSpecification" xmi:id="_xZwEkF_2EeiussJ5A9xGlQ" name="Message11SendEvent" covered="_5vRpQF_vEei3wLtnYCLwnw" message="_xZu2cF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:MessageOccurrenceSpecification" xmi:id="_xZwEkV_2EeiussJ5A9xGlQ" name="Message11ReceiveEvent" covered="_5nUAEF_vEei3wLtnYCLwnw" message="_xZu2cF_2EeiussJ5A9xGlQ"/>
+ <fragment xmi:type="uml:ExecutionOccurrenceSpecification" xmi:id="_qKr10V_2EeiussJ5A9xGlQ" name="Exec1Finish" covered="_5nUAEF_vEei3wLtnYCLwnw" execution="_qKqAoF_2EeiussJ5A9xGlQ"/>
+ <guard xmi:type="uml:InteractionConstraint" xmi:id="_byZwYF_wEei3wLtnYCLwnw" name="guard"/>
+ </operand>
+ </fragment>
+ <message xmi:type="uml:Message" xmi:id="_xBsJ4F_2EeiussJ5A9xGlQ" name="Message10" messageSort="asynchCall" receiveEvent="_xBxpcF_2EeiussJ5A9xGlQ" sendEvent="_xBxCYF_2EeiussJ5A9xGlQ"/>
+ <message xmi:type="uml:Message" xmi:id="_xZu2cF_2EeiussJ5A9xGlQ" name="Message11" messageSort="asynchCall" receiveEvent="_xZwEkV_2EeiussJ5A9xGlQ" sendEvent="_xZwEkF_2EeiussJ5A9xGlQ"/>
+ <message xmi:type="uml:Message" xmi:id="_yHfUUF_2EeiussJ5A9xGlQ" name="Message12" messageSort="asynchCall" receiveEvent="_yHi-sF_2EeiussJ5A9xGlQ" sendEvent="_yHhwkF_2EeiussJ5A9xGlQ"/>
+ </packagedElement>
+</uml:Model>
diff --git a/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/BugTests.java b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/BugTests.java
index 700c672586a..875fb41e54c 100644
--- a/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/BugTests.java
+++ b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/BugTests.java
@@ -36,6 +36,7 @@ import org.junit.runners.Suite.SuiteClasses;
CombinedFragmentRegressionTest.class,
TestCombinedFragmentOperandsLayout.class,
TestCFOperandsCoveredNodes.class,
+ TestCFOperandsSemanticCoverage.class,
})
public class BugTests {
diff --git a/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/TestCFOperandsSemanticCoverage.java b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/TestCFOperandsSemanticCoverage.java
new file mode 100644
index 00000000000..81c7802b81a
--- /dev/null
+++ b/tests/junit/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.sequence.tests/src/org/eclipse/papyrus/uml/diagram/sequence/tests/bug/TestCFOperandsSemanticCoverage.java
@@ -0,0 +1,482 @@
+/*****************************************************************************
+ * 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.diagram.sequence.tests.bug;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.RequestConstants;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeRequest;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.infra.gmfdiag.common.utils.DiagramEditPartsUtil;
+import org.eclipse.papyrus.junit.utils.rules.ActiveDiagram;
+import org.eclipse.papyrus.junit.utils.rules.PapyrusEditorFixture;
+import org.eclipse.papyrus.junit.utils.rules.PluginResource;
+import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes;
+import org.eclipse.papyrus.uml.diagram.sequence.requests.MoveSeparatorRequest;
+import org.eclipse.uml2.uml.ActionExecutionSpecification;
+import org.eclipse.uml2.uml.CombinedFragment;
+import org.eclipse.uml2.uml.ExecutionSpecification;
+import org.eclipse.uml2.uml.InteractionFragment;
+import org.eclipse.uml2.uml.InteractionOperand;
+import org.eclipse.uml2.uml.Message;
+import org.eclipse.uml2.uml.MessageEnd;
+import org.eclipse.uml2.uml.MessageOccurrenceSpecification;
+import org.eclipse.uml2.uml.util.UMLSwitch;
+import org.hamcrest.core.IsInstanceOf;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * <p>
+ * Test the semantic coverage update when the CombinedFragment and/or operands
+ * are updated visually (Creation/Deletion/Resize/Move).
+ * </p>
+ */
+// Test class for Bug 535097
+@PluginResource({ "resource/bugs/bug535097-OperandsSemantic.di", "resource/bugs/style.css" })
+@ActiveDiagram("SemanticCoverageTest")
+public class TestCFOperandsSemanticCoverage {
+
+ @Rule
+ public final PapyrusEditorFixture editor = new PapyrusEditorFixture();
+
+ private IGraphicalEditPart cfPart;
+ private IGraphicalEditPart operandPart;
+
+ private IGraphicalEditPart message10;
+ private IGraphicalEditPart message11;
+ private IGraphicalEditPart message12;
+
+ private IGraphicalEditPart exec1;
+ private IGraphicalEditPart exec2;
+
+ @Before
+ public void initParts() {
+ cfPart = (IGraphicalEditPart) editor.findEditPart("TestFragment", CombinedFragment.class);
+ operandPart = (IGraphicalEditPart) editor.findEditPart("InteractionOperand0", InteractionOperand.class);
+
+ message10 = (IGraphicalEditPart) editor.findEditPart("Message10", Message.class);
+ message11 = (IGraphicalEditPart) editor.findEditPart("Message11", Message.class);
+ message12 = (IGraphicalEditPart) editor.findEditPart("Message12", Message.class);
+
+ exec1 = (IGraphicalEditPart) editor.findEditPart("Exec1", ActionExecutionSpecification.class);
+ exec2 = (IGraphicalEditPart) editor.findEditPart("Exec2", ActionExecutionSpecification.class);
+ }
+
+ // The coverage is already set properly in the test model.
+ // This test is here to make sure that opening the diagram doesn't
+ // break the current values by incorrectly changing them.
+ @Test
+ public void testInitialCoverage() {
+ assertCovered(message10, operandPart);
+ assertCovered(message11, operandPart);
+ assertCovered(exec1, operandPart);
+
+ assertNotCovered(message12, operandPart);
+ assertNotCovered(exec2, operandPart);
+ }
+
+ @Test
+ public void testExpandCF() {
+ ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
+ request.setEditParts(cfPart);
+ request.setResizeDirection(PositionConstants.SOUTH_EAST);
+
+ // Expand the Fragment (South-East)
+ request.setSizeDelta(new Dimension(40, 160)); // Cover Exec2, and Message12#start
+
+ editor.execute(cfPart.getCommand(request));
+
+ assertCovered(message10, operandPart);
+ assertCovered(message11, operandPart);
+ assertCovered(exec1, operandPart);
+ assertCovered(exec2, operandPart);
+
+ assertCoverage(getSend(message12), getOperand(operandPart), true);
+ assertCoverage(getReceive(message12), getOperand(operandPart), false);
+ }
+
+ @Test
+ @Ignore
+ public void testExpandCFWidth() {
+ ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
+ request.setEditParts(cfPart);
+ request.setResizeDirection(PositionConstants.SOUTH_EAST);
+
+ // Expand the Fragment (South-East)
+ request.setSizeDelta(new Dimension(200, 160));
+
+ editor.execute(cfPart.getCommand(request));
+
+ // TODO Assert
+
+ // assertCovered(message10, operandPart);
+ // assertCovered(message11, operandPart);
+ // assertCovered(exec1, operandPart);
+ // assertCovered(exec2, operandPart);
+ //
+ // assertCoverage(getSend(message12), getOperand(operandPart), true);
+ // assertCoverage(getReceive(message12), getOperand(operandPart), false);
+ }
+
+ @Test
+ public void testShrinkCF() {
+ ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
+ request.setEditParts(cfPart);
+ request.setResizeDirection(PositionConstants.SOUTH_EAST);
+
+ // Shrink the Fragment (South-East)
+ request.setSizeDelta(new Dimension(0, -100)); // Between Message10 and Message11, only partially covers Exec1
+
+ editor.execute(cfPart.getCommand(request));
+
+ assertCovered(message10, operandPart);
+ assertNotCovered(message11, operandPart);
+
+ assertCoverage(getStart(exec1), getOperand(operandPart), true);
+ assertCoverage(getFinish(exec1), getOperand(operandPart), false);
+
+ assertNotCovered(exec2, operandPart);
+ assertNotCovered(message12, operandPart);
+ }
+
+ @Test
+ @Ignore
+ public void testCreateCombinedFragmentSpecificSize() {
+ // Create a fragment with a predefined size
+
+ }
+
+ @Test
+ public void testCreateOperand() {
+ IGraphicalEditPart operand2Part = createOperand(operandPart, at(200, 100, cfPart)); // Between Message10 and Message11
+
+ // Covered by the first operand
+ assertCovered(message10, operandPart);
+ assertCoverage(getStart(exec1), getOperand(operandPart), true);
+
+ // Covered by the second operand
+ assertCovered(message11, operand2Part);
+ assertCoverage(getFinish(exec1), getOperand(operand2Part), true);
+
+ // Not covered
+ assertNotCovered(message12, operandPart);
+ assertNotCovered(message12, operand2Part);
+ assertNotCovered(exec2, operandPart);
+ assertNotCovered(exec2, operand2Part);
+ }
+
+ @Test
+ public void testMoveCF() {
+ ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
+ request.setEditParts(cfPart);
+
+ // Move to the bottom
+ request.setMoveDelta(new Point(0, 180)); // Move over Exec2 and start of Message12
+ editor.execute(cfPart.getCommand(request));
+
+ assertNotCovered(exec1, operandPart);
+ assertNotCovered(message10, operandPart);
+ assertNotCovered(message11, operandPart);
+
+ assertCovered(exec2, operandPart);
+
+ assertCoverage(getSend(message12), getOperand(operandPart), true);
+ assertCoverage(getReceive(message12), getOperand(operandPart), false);
+
+ // Move again, to the right
+
+ request.setMoveDelta(new Point(280, 0)); // Move fully over Message12
+ editor.execute(cfPart.getCommand(request));
+
+ assertNotCovered(exec1, operandPart);
+ assertNotCovered(message10, operandPart);
+ assertNotCovered(message11, operandPart);
+ assertNotCovered(exec2, operandPart);
+
+ assertCovered(message12, operandPart);
+ }
+
+ @Test
+ public void testDeleteOperand() {
+ // Create a new operand, delete the first one, and check that the new
+ // one covers everything that was initially covered by the first
+ IGraphicalEditPart operand2Part = createOperand(operandPart, at(200, 100, cfPart)); // Between Message10 and Message11
+ editor.delete(operandPart);
+
+ assertCovered(message10, operand2Part);
+ assertCovered(message11, operand2Part);
+ assertCovered(exec1, operand2Part);
+
+ assertNotCovered(message12, operand2Part);
+ assertNotCovered(exec2, operand2Part);
+
+ // Same idea, with more operands. We'll need a bigger CF...
+ ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
+ request.setEditParts(cfPart);
+ request.setResizeDirection(PositionConstants.SOUTH_EAST);
+ request.setSizeDelta(new Dimension(40, 160)); // Cover Exec2, and Message12#start
+ editor.execute(cfPart.getCommand(request));
+
+ // Create some operands every 100px
+ IGraphicalEditPart operand3Part = createOperand(operand2Part, at(200, 100, cfPart)); // Between Message10 and Message11
+ IGraphicalEditPart operand4Part = createOperand(operand3Part, at(150, 200, cfPart)); // Between Exec1 and Exec2
+ IGraphicalEditPart operand5Part = createOperand(operand4Part, at(75, 300, cfPart)); // Middle of exec 2, below Message12
+
+ // Before deleting, make sure everything is what we expect...
+ assertCovered(message10, operand2Part);
+ assertCoverage(getStart(exec1), getOperand(operand2Part), true);
+
+ assertCovered(message11, operand3Part);
+ assertCoverage(getFinish(exec1), getOperand(operand3Part), true);
+
+ assertCoverage(getStart(exec2), getOperand(operand4Part), true);
+ assertCoverage(getSend(message12), getOperand(operand4Part), true);
+
+ assertCoverage(getFinish(exec2), getOperand(operand5Part), true);
+
+ // Now, start deleting some operands...
+ editor.delete(operand2Part); // Delete the top operand. Give its fragments to Operand3
+
+ assertCovered(message10, operand3Part);
+ assertCovered(message11, operand3Part);
+ assertCovered(exec1, operand3Part);
+
+ // 4 and 5 still expect the same coverage
+ assertCoverage(getStart(exec2), getOperand(operand4Part), true);
+ assertCoverage(getSend(message12), getOperand(operand4Part), true);
+ assertCoverage(getFinish(exec2), getOperand(operand5Part), true);
+
+ editor.delete(operand4Part); // Delete the middle operand. Give its fragments to Operand3
+
+ assertCovered(message10, operand3Part);
+ assertCovered(message11, operand3Part);
+ assertCovered(exec1, operand3Part);
+ assertCoverage(getStart(exec2), getOperand(operand3Part), true);
+ assertCoverage(getSend(message12), getOperand(operand3Part), true);
+
+ // 5 still expects the same coverage
+ assertCoverage(getFinish(exec2), getOperand(operand5Part), true);
+
+ editor.delete(operand5Part); // Delete the bottom operand. Give its fragments to Operand3
+
+ assertCovered(message10, operand3Part);
+ assertCovered(message11, operand3Part);
+ assertCovered(exec1, operand3Part);
+ assertCoverage(getStart(exec2), getOperand(operand3Part), true);
+ assertCoverage(getSend(message12), getOperand(operand3Part), true);
+ assertCoverage(getFinish(exec2), getOperand(operand3Part), true);
+ }
+
+ @Test
+ public void testMoveOperandSeparator() {
+ // First, expand the CF...
+ ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
+ request.setEditParts(cfPart);
+ request.setResizeDirection(PositionConstants.SOUTH_EAST);
+ request.setSizeDelta(new Dimension(40, 160)); // Cover Exec2, and Message12#start
+ editor.execute(cfPart.getCommand(request));
+
+ // ...and create some operands...
+ IGraphicalEditPart operand2Part = createOperand(operandPart, at(200, 100, cfPart)); // Between Message10 and Message11
+ IGraphicalEditPart operand3Part = createOperand(operand2Part, at(150, 200, cfPart)); // Between Exec1 and Exec2
+ IGraphicalEditPart operand4Part = createOperand(operand3Part, at(75, 300, cfPart)); // Middle of exec 2, below Message12
+
+ // ...Check the initial state...
+ assertCovered(message10, operandPart);
+ assertCoverage(getStart(exec1), getOperand(operandPart), true);
+
+ assertCovered(message11, operand2Part);
+ assertCoverage(getFinish(exec1), getOperand(operand2Part), true);
+
+ assertCoverage(getStart(exec2), getOperand(operand3Part), true);
+ assertCoverage(getSend(message12), getOperand(operand3Part), true);
+
+ assertCoverage(getFinish(exec2), getOperand(operand4Part), true);
+
+ // Prepare the request to move the first separator...
+ MoveSeparatorRequest resizeOperands = new MoveSeparatorRequest(0);
+ resizeOperands.setLocation(at(100, 0, operandPart));
+ resizeOperands.setEditParts(Collections.singletonList(cfPart));
+
+ // Move the first separator down
+ resizeOperands.setMoveDelta(new Point(0, 80)); // Below Message 11 and Exec1
+ editor.execute(cfPart.getCommand(resizeOperands));
+
+ assertCovered(message10, operandPart);
+ assertCovered(message11, operandPart);
+ assertCovered(exec1, operandPart);
+
+ // Move the first separator up
+ resizeOperands.setMoveDelta(new Point(0, -150)); // Above message 10 and exec1
+ editor.execute(cfPart.getCommand(resizeOperands));
+
+ assertCovered(message10, operand2Part);
+ assertCovered(message11, operand2Part);
+ assertCovered(exec1, operand2Part);
+
+ // Last separator...
+ resizeOperands = new MoveSeparatorRequest(2);
+ resizeOperands.setLocation(at(100, 0, operand4Part));
+ resizeOperands.setEditParts(Collections.singletonList(cfPart));
+
+ // Move the last separator down
+ resizeOperands.setMoveDelta(new Point(0, 45)); // Below Exec2
+ editor.execute(cfPart.getCommand(resizeOperands));
+
+ assertCovered(exec2, operand3Part);
+ assertCoverage(getSend(message12), getOperand(operand3Part), true);
+
+ // Move the last separator up
+ resizeOperands.setMoveDelta(new Point(0, -100)); // Between start of Exec2 and start of message12
+ editor.execute(cfPart.getCommand(resizeOperands));
+
+ assertCoverage(getStart(exec2), getOperand(operand3Part), true);
+ // --- separator is here ---
+ assertCoverage(getSend(message12), getOperand(operand4Part), true);
+ assertCoverage(getFinish(exec2), getOperand(operand4Part), true);
+ }
+
+ private void assertCovered(IGraphicalEditPart coveredPart, IGraphicalEditPart operandPart) {
+ assertCoverage(coveredPart, operandPart, true);
+ }
+
+ private void assertNotCovered(IGraphicalEditPart coveredPart, IGraphicalEditPart operandPart) {
+ assertCoverage(coveredPart, operandPart, false);
+ }
+
+ private void assertCoverage(IGraphicalEditPart coveredPart, IGraphicalEditPart operandPart, boolean expectedCoverage) {
+ EObject semantic = coveredPart.getNotationView().getElement();
+ InteractionOperand operand = getOperand(operandPart);
+
+ assertCoverage(semantic, operand, expectedCoverage);
+ }
+
+ private InteractionOperand getOperand(IGraphicalEditPart operandPart) {
+ return (InteractionOperand) operandPart.getNotationView().getElement();
+ }
+
+ private void assertCoverage(EObject semantic, InteractionOperand operand, boolean expectedCoverage) {
+ new UMLSwitch<Void>() {
+ @Override
+ public Void caseMessage(Message object) {
+ assertCoverage(object, operand, expectedCoverage);
+ return null;
+ }
+
+ @Override
+ public Void caseExecutionSpecification(ExecutionSpecification object) {
+ assertCoverage(object, operand, expectedCoverage);
+ return null;
+ }
+ }.doSwitch(semantic);
+ }
+
+ private MessageEnd getSend(IGraphicalEditPart messageEditPart) {
+ return ((Message) messageEditPart.getNotationView().getElement()).getSendEvent();
+ }
+
+ private MessageEnd getReceive(IGraphicalEditPart messageEditPart) {
+ return ((Message) messageEditPart.getNotationView().getElement()).getReceiveEvent();
+ }
+
+ private InteractionFragment getStart(IGraphicalEditPart execSpecEditPart) {
+ return ((ExecutionSpecification) execSpecEditPart.getNotationView().getElement()).getStart();
+ }
+
+ private InteractionFragment getFinish(IGraphicalEditPart execSpecEditPart) {
+ return ((ExecutionSpecification) execSpecEditPart.getNotationView().getElement()).getFinish();
+ }
+
+ private void assertCoverage(Message message, InteractionOperand operand, boolean expectedCoverage) {
+ assertCoverage(message.getSendEvent(), operand, expectedCoverage);
+ assertCoverage(message.getReceiveEvent(), operand, expectedCoverage);
+ }
+
+ private void assertCoverage(MessageEnd messageEnd, InteractionOperand operand, boolean expectedCoverage) {
+ Assert.assertThat(messageEnd, IsInstanceOf.instanceOf(MessageOccurrenceSpecification.class));
+ assertCoverage((InteractionFragment) messageEnd, operand, expectedCoverage);
+ }
+
+ private void assertCoverage(ExecutionSpecification exec, InteractionOperand operand, boolean expectedCoverage) {
+ assertCoverage(exec.getStart(), operand, expectedCoverage);
+ assertCoverage(exec.getFinish(), operand, expectedCoverage);
+ }
+
+ private void assertCoverage(InteractionFragment fragment, InteractionOperand operand, boolean expectedCoverage) {
+ Assert.assertEquals(expectedCoverage, operand.getFragments().contains(fragment));
+ }
+
+ // Don't use editor.createShape(), because we need a special type of request to create operands.
+ // The "InsertAt" behavior will only be computed if we use a CreateUnspecifiedTypeRequest (From the palette)
+ // and target an Operand. The Operand will then be responsible for setting the InsertAt parameter
+ // and delegate to the CombinedFragment compartment for the actual creation
+ private GraphicalEditPart createOperand(IGraphicalEditPart targetVisualPart, Point location) {
+ CreateUnspecifiedTypeRequest request = new CreateUnspecifiedTypeRequest(Collections.singletonList(UMLElementTypes.InteractionOperand_Shape), targetVisualPart.getDiagramPreferencesHint());
+
+ request.setLocation(location);
+
+ EditPart target = targetVisualPart.getTargetEditPart(request);
+ assertThat("No target edit part", target, notNullValue());
+ org.eclipse.gef.commands.Command command = target.getCommand(request);
+ editor.execute(command);
+
+ // Find the new edit-part
+ Object result = request.getNewObject();
+ Assert.assertThat(result, instanceOf(Collection.class));
+ Collection<?> results = (Collection<?>) result;
+ return results.stream()
+ .filter(ViewDescriptor.class::isInstance).map(ViewDescriptor.class::cast)
+ .map(desc -> desc.getAdapter(View.class)).map(View.class::cast)
+ .filter(Objects::nonNull)
+ .map(view -> DiagramEditPartsUtil.getEditPartFromView(view, targetVisualPart))
+ .filter(GraphicalEditPart.class::isInstance).map(GraphicalEditPart.class::cast)
+ .filter(Objects::nonNull)
+ .findAny().orElseThrow(() -> new IllegalStateException("Could not find new shape edit-part"));
+ }
+
+ // Convert a point that is relative to the given part to a point relative to the current Viewport (Taking zoom & translate into account).
+ // This can be used to get a "Mouse Location" to configure Requests
+ private static Point at(int x, int y, IGraphicalEditPart relativeTo) {
+ Point at = new Point(x, y);
+
+ IFigure figure = relativeTo.getContentPane();
+ Point layoutOrigin = figure.getClientArea().getLocation();
+
+ at.performTranslate(layoutOrigin.x, layoutOrigin.y);
+ figure.translateToParent(at);
+ figure.translateToAbsolute(at);
+
+ return at;
+ }
+
+}