Skip to content

Commit 5385e7e

Browse files
committed
[1233] Add new tools to create State sub actions in general view
Bug: eclipse-syson#1233 Signed-off-by: Jerome Gout <[email protected]>
1 parent 37063f9 commit 5385e7e

File tree

8 files changed

+305
-62
lines changed

8 files changed

+305
-62
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- https://github.com/eclipse-syson/syson/issues/1247[#1247] [explorer] Type new `ViewUsage` from _Explorer_ view with _General View_ `ViewDefinition`.
2424
When end-users click on _New Object_ on a semantic element, and select a `ViewUsage`, then a `ViewUsage` typed by default with the _General View_ `ViewDefinition` from the standard library will be created.
2525
- https://github.com/eclipse-syson/syson/issues/1252[#1252] [exort] Implement textual export of `TriggerInvocationExpression`.
26+
- https://github.com/eclipse-syson/syson/issues/1233[#1233] [general-view] Add a creation tool of State sub actions with referenced action inside State elements
2627

2728
=== New features
2829

backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeStateTransitionCreationTests.java

Lines changed: 111 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,22 @@
1212
*******************************************************************************/
1313
package org.eclipse.syson.application.controllers.diagrams.general.view;
1414

15+
import static org.assertj.core.api.Assertions.assertThat;
16+
1517
import java.time.Duration;
18+
import java.util.List;
1619
import java.util.UUID;
1720
import java.util.concurrent.atomic.AtomicReference;
1821
import java.util.stream.Stream;
1922

23+
import org.apache.commons.lang3.StringUtils;
2024
import org.eclipse.emf.ecore.EClass;
2125
import org.eclipse.emf.ecore.EReference;
2226
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput;
2327
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload;
28+
import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariable;
29+
import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariableType;
30+
import org.eclipse.sirius.components.core.api.IIdentityService;
2431
import org.eclipse.sirius.components.core.api.IObjectSearchService;
2532
import org.eclipse.sirius.components.diagrams.Diagram;
2633
import org.eclipse.sirius.components.view.diagram.DiagramDescription;
@@ -46,8 +53,14 @@
4653
import org.eclipse.syson.services.diagrams.api.IGivenDiagramDescription;
4754
import org.eclipse.syson.services.diagrams.api.IGivenDiagramReference;
4855
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
56+
import org.eclipse.syson.sysml.ActionUsage;
57+
import org.eclipse.syson.sysml.PerformActionUsage;
58+
import org.eclipse.syson.sysml.ReferenceSubsetting;
59+
import org.eclipse.syson.sysml.StateSubactionKind;
60+
import org.eclipse.syson.sysml.StateSubactionMembership;
4961
import org.eclipse.syson.sysml.SysmlPackage;
5062
import org.eclipse.syson.util.IDescriptionNameGenerator;
63+
import org.jetbrains.annotations.NotNull;
5164
import org.junit.jupiter.api.AfterEach;
5265
import org.junit.jupiter.api.BeforeEach;
5366
import org.junit.jupiter.params.ParameterizedTest;
@@ -104,6 +117,9 @@ public class GVSubNodeStateTransitionCreationTests extends AbstractIntegrationTe
104117
@Autowired
105118
private DiagramComparator diagramComparator;
106119

120+
@Autowired
121+
private IIdentityService identityService;
122+
107123
private DiagramDescriptionIdProvider diagramDescriptionIdProvider;
108124

109125
private Step<DiagramRefreshedEventPayload> verifier;
@@ -120,11 +136,11 @@ public class GVSubNodeStateTransitionCreationTests extends AbstractIntegrationTe
120136

121137
private SemanticCheckerService semanticCheckerService;
122138

123-
private static Stream<Arguments> stateUsageSiblingNodeParameters() {
139+
private static Stream<Arguments> stateSubactionsParameters() {
124140
return Stream.of(
125-
Arguments.of(SysmlPackage.eINSTANCE.getActionUsage(), SysmlPackage.eINSTANCE.getStateUsage_EntryAction(), "New Entry Action", 4),
126-
Arguments.of(SysmlPackage.eINSTANCE.getActionUsage(), SysmlPackage.eINSTANCE.getStateUsage_DoAction(), "New Do Action", 4),
127-
Arguments.of(SysmlPackage.eINSTANCE.getActionUsage(), SysmlPackage.eINSTANCE.getStateUsage_ExitAction(), "New Exit Action", 4))
141+
Arguments.of(StateSubactionKind.ENTRY),
142+
Arguments.of(StateSubactionKind.DO),
143+
Arguments.of(StateSubactionKind.EXIT))
128144
.map(TestNameGenerator::namedArguments);
129145
}
130146

@@ -138,14 +154,6 @@ private static Stream<Arguments> stateUsageChildNodeParameters() {
138154
.map(TestNameGenerator::namedArguments);
139155
}
140156

141-
private static Stream<Arguments> stateDefinitionSiblingNodeParameters() {
142-
return Stream.of(
143-
Arguments.of(SysmlPackage.eINSTANCE.getActionUsage(), SysmlPackage.eINSTANCE.getStateDefinition_EntryAction(), "New Entry Action", 4),
144-
Arguments.of(SysmlPackage.eINSTANCE.getActionUsage(), SysmlPackage.eINSTANCE.getStateDefinition_DoAction(), "New Do Action", 4),
145-
Arguments.of(SysmlPackage.eINSTANCE.getActionUsage(), SysmlPackage.eINSTANCE.getStateDefinition_ExitAction(), "New Exit Action", 4))
146-
.map(TestNameGenerator::namedArguments);
147-
}
148-
149157
private static Stream<Arguments> stateDefinitionChildNodeParameters() {
150158
return Stream.of(
151159
Arguments.of(SysmlPackage.eINSTANCE.getDocumentation(), DOC_COMPARTMENT, SysmlPackage.eINSTANCE.getElement_Documentation(), "New Documentation"),
@@ -185,16 +193,98 @@ public void tearDown() {
185193
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
186194
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
187195
@ParameterizedTest
188-
@MethodSource("stateUsageSiblingNodeParameters")
189-
public void createStateUsageSiblingNodes(EClass childEClass, EReference containmentReference, String creationToolName, int compartmentCount) {
190-
EClass parentEClass = SysmlPackage.eINSTANCE.getStateUsage();
191-
String parentLabel = "state";
196+
@MethodSource("stateSubactionsParameters")
197+
public void createStateUsageSubactionNode(StateSubactionKind kind) {
198+
String toolName = "New " + StringUtils.capitalize(kind.getName()) + " Action";
192199

193-
this.creationTestsService.createNode(this.verifier, this.diagramDescriptionIdProvider, this.diagram, parentEClass, parentLabel, creationToolName);
194-
// the action is created inside a list compartment and outside as a sibling node
195-
this.diagramCheckerService.checkDiagram(this.diagramCheckerService.getSiblingNodeGraphicalChecker(this.diagram, this.diagramDescriptionIdProvider, childEClass, compartmentCount, 2),
196-
this.diagram, this.verifier);
197-
this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass), this.verifier);
200+
this.createStateSubactionNode(kind, SysmlPackage.eINSTANCE.getStateUsage(), "state", toolName);
201+
}
202+
203+
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
204+
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
205+
@ParameterizedTest
206+
@MethodSource("stateSubactionsParameters")
207+
public void createStateUsageSubactionWithReferencedActionNode(StateSubactionKind kind) {
208+
String toolName = "New " + StringUtils.capitalize(kind.getName()) + " Action with referenced Action";
209+
var params = List.of(new ToolVariable("selectedObject", GeneralViewWithTopNodesTestProjectData.SemanticIds.ACTION_USAGE_ID , ToolVariableType.OBJECT_ID));
210+
211+
this.createStateSubactionWithReferencedActionNode(kind, SysmlPackage.eINSTANCE.getStateUsage(), "state", toolName, params);
212+
}
213+
214+
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
215+
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
216+
@ParameterizedTest
217+
@MethodSource("stateSubactionsParameters")
218+
public void createStateDefinitionSubactionNode(StateSubactionKind kind) {
219+
String toolName = "New " + StringUtils.capitalize(kind.getName()) + " Action";
220+
221+
this.createStateSubactionNode(kind, SysmlPackage.eINSTANCE.getStateDefinition(), "StateDefinition", toolName);
222+
}
223+
224+
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
225+
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
226+
@ParameterizedTest
227+
@MethodSource("stateSubactionsParameters")
228+
public void createStateDefinitionSubactionWithReferencedActionNode(StateSubactionKind kind) {
229+
String toolName = "New " + StringUtils.capitalize(kind.getName()) + " Action with referenced Action";
230+
var params = List.of(new ToolVariable("selectedObject", GeneralViewWithTopNodesTestProjectData.SemanticIds.ACTION_USAGE_ID , ToolVariableType.OBJECT_ID));
231+
232+
this.createStateSubactionWithReferencedActionNode(kind, SysmlPackage.eINSTANCE.getStateDefinition(), "StateDefinition", toolName, params);
233+
}
234+
235+
private void createStateSubactionNode(StateSubactionKind kind, EClass parentEClass, String parentLabel, String toolName) {
236+
this.creationTestsService.createNode(this.verifier, this.diagramDescriptionIdProvider, this.diagram, parentEClass, parentLabel, toolName);
237+
238+
String[] subActionId = new String[1];
239+
IDiagramChecker diagramChecker = (initialDiagram, newDiagram) -> {
240+
new CheckDiagramElementCount(this.diagramComparator)
241+
// only the new subaction should be created
242+
.hasNewNodeCount(1)
243+
.hasNewEdgeCount(0)
244+
.check(initialDiagram, newDiagram);
245+
var node = this.diagramComparator.newNodes(initialDiagram, newDiagram).get(0);
246+
subActionId[0] = node.getTargetObjectId();
247+
};
248+
this.diagramCheckerService.checkDiagram(diagramChecker, this.diagram, this.verifier);
249+
250+
this.semanticCheckerService.checkElement(this.verifier, PerformActionUsage.class, () -> subActionId[0], subaction -> {
251+
// new subaction should be owned by a StateSubactionMembership with the correct kind
252+
var parentMembership = subaction.eContainer();
253+
assertThat(parentMembership).isInstanceOf(StateSubactionMembership.class);
254+
var stateSubactionMembership = (StateSubactionMembership) parentMembership;
255+
assertThat(stateSubactionMembership.getKind()).isEqualTo(kind);
256+
// subaction has no owned membership
257+
assertThat(subaction.getOwnedRelationship()).hasSize(0);
258+
});
259+
}
260+
261+
private void createStateSubactionWithReferencedActionNode(StateSubactionKind kind, EClass parentEClass, String parentLabel, String toolName, List<@NotNull ToolVariable> params) {
262+
this.creationTestsService.createNode(this.verifier, this.diagramDescriptionIdProvider, this.diagram, parentEClass, parentLabel, toolName, params);
263+
264+
String[] subActionId = new String[1];
265+
IDiagramChecker diagramChecker = (initialDiagram, newDiagram) -> {
266+
new CheckDiagramElementCount(this.diagramComparator)
267+
// only the new subaction should be created
268+
.hasNewNodeCount(1)
269+
.hasNewEdgeCount(0)
270+
.check(initialDiagram, newDiagram);
271+
var node = this.diagramComparator.newNodes(initialDiagram, newDiagram).get(0);
272+
subActionId[0] = node.getTargetObjectId();
273+
};
274+
this.diagramCheckerService.checkDiagram(diagramChecker, this.diagram, this.verifier);
275+
276+
this.semanticCheckerService.checkElement(this.verifier, PerformActionUsage.class, () -> subActionId[0], subaction -> {
277+
var membership = subaction.eContainer();
278+
assertThat(membership).isInstanceOf(StateSubactionMembership.class);
279+
var stateSubactionMembership = (StateSubactionMembership) membership;
280+
assertThat(stateSubactionMembership.getKind()).isEqualTo(kind);
281+
// check that the new sub action contains the reference subsetting to the existing action
282+
var memberships = subaction.getOwnedRelationship();
283+
assertThat(memberships.get(0)).isInstanceOf(ReferenceSubsetting.class);
284+
var referenceSubsetting = (ReferenceSubsetting) memberships.get(0);
285+
assertThat(referenceSubsetting.getReferencedFeature()).isInstanceOf(ActionUsage.class);
286+
assertThat(this.identityService.getId(referenceSubsetting.getReferencedFeature())).isEqualTo(GeneralViewWithTopNodesTestProjectData.SemanticIds.ACTION_USAGE_ID);
287+
});
198288
}
199289

200290
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@@ -231,21 +321,6 @@ public void createStateUsageChildNodes(EClass childEClass, String compartmentNam
231321
}
232322
}
233323

234-
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
235-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
236-
@ParameterizedTest
237-
@MethodSource("stateDefinitionSiblingNodeParameters")
238-
public void createStateDefinitionSiblingNodes(EClass childEClass, EReference containmentReference, String creationToolName, int compartmentCount) {
239-
EClass parentEClass = SysmlPackage.eINSTANCE.getStateDefinition();
240-
String parentLabel = "StateDefinition";
241-
242-
this.creationTestsService.createNode(this.verifier, this.diagramDescriptionIdProvider, this.diagram, parentEClass, parentLabel, creationToolName);
243-
// the action is created inside a list compartment and outside as a sibling node
244-
this.diagramCheckerService.checkDiagram(this.diagramCheckerService.getSiblingNodeGraphicalChecker(this.diagram, this.diagramDescriptionIdProvider, childEClass, compartmentCount, 2),
245-
this.diagram, this.verifier);
246-
this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker(parentLabel, containmentReference, childEClass), this.verifier);
247-
}
248-
249324
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
250325
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
251326
@ParameterizedTest

backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.eclipse.syson.sysml.ParameterMembership;
6262
import org.eclipse.syson.sysml.PartDefinition;
6363
import org.eclipse.syson.sysml.PartUsage;
64+
import org.eclipse.syson.sysml.PerformActionUsage;
6465
import org.eclipse.syson.sysml.PortUsage;
6566
import org.eclipse.syson.sysml.ReferenceSubsetting;
6667
import org.eclipse.syson.sysml.ReferenceUsage;
@@ -71,6 +72,7 @@
7172
import org.eclipse.syson.sysml.Specialization;
7273
import org.eclipse.syson.sysml.StakeholderMembership;
7374
import org.eclipse.syson.sysml.StateDefinition;
75+
import org.eclipse.syson.sysml.StateSubactionKind;
7476
import org.eclipse.syson.sysml.StateSubactionMembership;
7577
import org.eclipse.syson.sysml.StateUsage;
7678
import org.eclipse.syson.sysml.SubjectMembership;
@@ -1137,6 +1139,35 @@ public BindingConnectorAsUsage createBindingConnectorAsUsage(Feature source, Fea
11371139
return bindingConnectorAsUsage;
11381140
}
11391141

1142+
/**
1143+
* Creates a state sub action (entry, do or exit actions) as a child of the given StateUsage or StateDefinition.
1144+
*
1145+
* @param self
1146+
* the StateUsage or StateDefinition owning the sub action
1147+
* @param performedAction
1148+
* an ActionUsage or <code>null</code>. If set the new PerformAction should reference this action.
1149+
* @param kindLiteral
1150+
* the kind of the StateSubactionMembership owning the PerformAction
1151+
* @return the new PerformAction or null if self is not a State
1152+
*/
1153+
public PerformActionUsage createStateSubaction(Element self, ActionUsage performedAction, String kindLiteral) {
1154+
if (self instanceof StateUsage || self instanceof StateDefinition) {
1155+
StateSubactionMembership stateSubactionMembership = (StateSubactionMembership) this.createMembership(self, SysmlPackage.eINSTANCE.getStateSubactionMembership());
1156+
stateSubactionMembership.setKind(StateSubactionKind.get(kindLiteral));
1157+
var performAction = SysmlFactory.eINSTANCE.createPerformActionUsage();
1158+
stateSubactionMembership.getOwnedRelatedElement().add(performAction);
1159+
this.elementInitializerSwitch.doSwitch(performAction);
1160+
if (performedAction != null) {
1161+
// set the reference subsetting relationship to the performed action
1162+
var referenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting();
1163+
referenceSubsetting.setReferencedFeature(performedAction);
1164+
performAction.getOwnedRelationship().add(referenceSubsetting);
1165+
}
1166+
return performAction;
1167+
}
1168+
return null;
1169+
}
1170+
11401171
private boolean isInSameGraphicalContainer(Node sourceNode, Node targetNode, IDiagramService diagramService) {
11411172
Diagram diagram = diagramService.getDiagramContext().getDiagram();
11421173
var sourceParentNode = new NodeFinder(diagram).getParent(sourceNode);

backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewToolService.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,28 @@ public List<? extends Object> getActorSelectionDialogChildren(Object selectionDi
13161316
return this.getChildrenWithInstancesOf(selectionDialogTreeElement, SysmlPackage.eINSTANCE.getPartUsage());
13171317
}
13181318

1319+
/**
1320+
* Provides the root elements in the tree of the selection dialog for the State sub actions creation tool.
1321+
*
1322+
* @param editingContext
1323+
* the (non-{@code null}) {@link IEditingContext}.
1324+
* @return the (non-{@code null}) {@link List} of all {@link Resource} that contain at least one {@link ActionUsage}.
1325+
*/
1326+
public List<Resource> getStateSubactionReferenceSelectionDialogElements(IEditingContext editingContext) {
1327+
return this.getAllResourcesWithInstancesOf(editingContext, SysmlPackage.eINSTANCE.getActionUsage());
1328+
}
1329+
1330+
/**
1331+
* Provides the children of element in the tree of the selection dialog for the State sub actions creation tool.
1332+
*
1333+
* @param selectionDialogTreeElement
1334+
* a (non-{@code null}) selection dialog tree element.
1335+
* @return the (non-{@code null}) {@link List} of all children that contain (possibly indirectly) an {@link ActionUsage}.
1336+
*/
1337+
public List<? extends Object> getStateSubactionReferenceSelectionDialogChildren(Object selectionDialogTreeElement) {
1338+
return this.getChildrenWithInstancesOf(selectionDialogTreeElement, SysmlPackage.eINSTANCE.getActionUsage());
1339+
}
1340+
13191341
private List<Resource> getAllResourcesWithInstancesOf(IEditingContext editingContext, EClassifier eClassifier) {
13201342
Objects.requireNonNull(editingContext);
13211343

0 commit comments

Comments
 (0)