Skip to content

Commit ec9b760

Browse files
gcoutableAxelRICHARD
authored andcommitted
[2242] Allow creating a ConcernUsage from a Requirement in Explorer
Bug: #2242 Signed-off-by: Guillaume Coutable <guillaume.coutable@obeo.fr>
1 parent 8760048 commit ec9b760

6 files changed

Lines changed: 153 additions & 5 deletions

File tree

CHANGELOG.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Disabling the _Hide expression internals_ filter in the _Explorer_ view allows t
3838
- https://github.com/eclipse-syson/syson/issues/2231[#2231] [diagrams] Add a new tool to create a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes.
3939
- https://github.com/eclipse-syson/syson/issues/2231[#2231] [diagrams] Add the support for the _frames_ compartment graphical node in `RequirementUsage` and `RequirementDefinition` graphical nodes.
4040
- https://github.com/eclipse-syson/syson/issues/2235[#2235] [diagrams] Leverage the selection dialog to improve the graphical node tool creating a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes.
41+
- https://github.com/eclipse-syson/syson/issues/2242[#2242] [explorer] Add two options to the dialog creating a child element of `RequirementUsage` or `RequirementDefinition` tree items.
42+
One creates a `ConcernUsage` and another one creates `FramedConcernMembership`.
4143

4244
== v2026.5.0
4345

backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/GetChildCreationSwitch.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.syson.sysml.Definition;
2525
import org.eclipse.syson.sysml.EnumerationDefinition;
2626
import org.eclipse.syson.sysml.FeatureMembership;
27+
import org.eclipse.syson.sysml.FramedConcernMembership;
2728
import org.eclipse.syson.sysml.InterfaceUsage;
2829
import org.eclipse.syson.sysml.ItemUsage;
2930
import org.eclipse.syson.sysml.Namespace;
@@ -134,6 +135,13 @@ public List<EClass> caseFeatureMembership(FeatureMembership object) {
134135
return childrenCandidates;
135136
}
136137

138+
@Override
139+
public List<EClass> caseFramedConcernMembership(FramedConcernMembership object) {
140+
List<EClass> childrenCandidates = new ArrayList<>();
141+
childrenCandidates.add(SysmlPackage.eINSTANCE.getConcernUsage());
142+
return childrenCandidates;
143+
}
144+
137145
@Override
138146
public List<EClass> caseInterfaceUsage(InterfaceUsage object) {
139147
List<EClass> childrenCandidates = new ArrayList<>();
@@ -224,6 +232,8 @@ public List<EClass> caseRequirementDefinition(RequirementDefinition object) {
224232
List<EClass> childrenCandidates = new ArrayList<>();
225233
childrenCandidates.addAll(this.caseDefinition(object));
226234
childrenCandidates.add(SysmlPackage.eINSTANCE.getSubjectMembership());
235+
childrenCandidates.add(SysmlPackage.eINSTANCE.getFramedConcernMembership());
236+
childrenCandidates.add(SysmlPackage.eINSTANCE.getConcernUsage());
227237
return childrenCandidates;
228238
}
229239

@@ -232,6 +242,8 @@ public List<EClass> caseRequirementUsage(RequirementUsage object) {
232242
List<EClass> childrenCandidates = new ArrayList<>();
233243
childrenCandidates.addAll(this.caseUsage(object));
234244
childrenCandidates.add(SysmlPackage.eINSTANCE.getSubjectMembership());
245+
childrenCandidates.add(SysmlPackage.eINSTANCE.getFramedConcernMembership());
246+
childrenCandidates.add(SysmlPackage.eINSTANCE.getConcernUsage());
235247
return childrenCandidates;
236248
}
237249

backend/application/syson-application-configuration/src/test/java/org/eclipse/syson/application/services/GetChildCreationSwitchTest.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2024, 2025 Obeo.
2+
* Copyright (c) 2024, 2026 Obeo.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -19,6 +19,7 @@
1919
import org.eclipse.emf.ecore.EClass;
2020
import org.eclipse.syson.sysml.SysmlFactory;
2121
import org.eclipse.syson.sysml.SysmlPackage;
22+
import org.junit.jupiter.api.DisplayName;
2223
import org.junit.jupiter.api.Test;
2324

2425
/**
@@ -28,6 +29,7 @@
2829
*/
2930
public class GetChildCreationSwitchTest {
3031

32+
@DisplayName("Check the list of children that can be created from a Package")
3133
@Test
3234
public void testPackageChildren() {
3335
List<EClass> children = new GetChildCreationSwitch().doSwitch(SysmlFactory.eINSTANCE.createPackage());
@@ -47,6 +49,7 @@ public void testPackageChildren() {
4749
|| SysmlPackage.eINSTANCE.getPackage().isSuperTypeOf(eClass));
4850
}
4951

52+
@DisplayName("Check the list of children that can be created from a Namespace")
5053
@Test
5154
public void testNamespaceChildren() {
5255
List<EClass> children = new GetChildCreationSwitch().doSwitch(SysmlFactory.eINSTANCE.createNamespace());
@@ -66,6 +69,7 @@ public void testNamespaceChildren() {
6669
|| SysmlPackage.eINSTANCE.getPackage().isSuperTypeOf(eClass));
6770
}
6871

72+
@DisplayName("Check the list of children that can be created from a ViewUsage")
6973
@Test
7074
public void testViewUsageChildren() {
7175
List<EClass> children = new GetChildCreationSwitch().doSwitch(SysmlFactory.eINSTANCE.createViewUsage());
@@ -79,4 +83,63 @@ public void testViewUsageChildren() {
7983
children.removeAll(expectedChildren);
8084
assertThat(children).isEmpty();
8185
}
86+
87+
@DisplayName("Check the list of children that can be created from a RequirementDefinition")
88+
@Test
89+
public void testRequirementDefinitionChildren() {
90+
List<EClass> children = new GetChildCreationSwitch().doSwitch(SysmlFactory.eINSTANCE.createRequirementDefinition());
91+
List<EClass> expectedChildren = List.of(
92+
SysmlPackage.eINSTANCE.getSubclassification(),
93+
SysmlPackage.eINSTANCE.getDocumentation(),
94+
SysmlPackage.eINSTANCE.getComment(),
95+
SysmlPackage.eINSTANCE.getTextualRepresentation(),
96+
SysmlPackage.eINSTANCE.getSubjectMembership(),
97+
SysmlPackage.eINSTANCE.getFramedConcernMembership(),
98+
SysmlPackage.eINSTANCE.getConcernUsage()
99+
);
100+
assertThat(children).containsAll(expectedChildren);
101+
children.removeAll(expectedChildren);
102+
assertThat(children).allMatch(eClass -> {
103+
boolean authorizedClasses = SysmlPackage.eINSTANCE.getUsage().isSuperTypeOf(eClass) || SysmlPackage.eINSTANCE.getImport().isSuperTypeOf(eClass);
104+
return !eClass.isAbstract() && !eClass.isInterface() && authorizedClasses;
105+
});
106+
}
107+
108+
@DisplayName("Check the list of children that can be created from a RequirementUsage")
109+
@Test
110+
public void testRequirementUsageChildren() {
111+
List<EClass> children = new GetChildCreationSwitch().doSwitch(SysmlFactory.eINSTANCE.createRequirementUsage());
112+
List<EClass> expectedChildren = List.of(
113+
SysmlPackage.eINSTANCE.getAttributeUsage(),
114+
SysmlPackage.eINSTANCE.getFeatureTyping(),
115+
SysmlPackage.eINSTANCE.getSubsetting(),
116+
SysmlPackage.eINSTANCE.getRedefinition(),
117+
SysmlPackage.eINSTANCE.getReferenceSubsetting(),
118+
SysmlPackage.eINSTANCE.getLiteralBoolean(),
119+
SysmlPackage.eINSTANCE.getLiteralInfinity(),
120+
SysmlPackage.eINSTANCE.getLiteralInteger(),
121+
SysmlPackage.eINSTANCE.getLiteralRational(),
122+
SysmlPackage.eINSTANCE.getLiteralString(),
123+
SysmlPackage.eINSTANCE.getFeatureMembership(),
124+
SysmlPackage.eINSTANCE.getDocumentation(),
125+
SysmlPackage.eINSTANCE.getComment(),
126+
SysmlPackage.eINSTANCE.getTextualRepresentation(),
127+
SysmlPackage.eINSTANCE.getSubjectMembership(),
128+
SysmlPackage.eINSTANCE.getFramedConcernMembership(),
129+
SysmlPackage.eINSTANCE.getConcernUsage()
130+
);
131+
assertThat(children).containsAll(expectedChildren);
132+
children.removeAll(expectedChildren);
133+
assertThat(children).isEmpty();
134+
}
135+
136+
@DisplayName("Check the list of children that can be created from a FramedConcernMembership")
137+
@Test
138+
public void testFramedConcernMembership() {
139+
List<EClass> children = new GetChildCreationSwitch().doSwitch(SysmlFactory.eINSTANCE.createFramedConcernMembership());
140+
List<EClass> expectedChildren = List.of(SysmlPackage.eINSTANCE.getConcernUsage());
141+
assertThat(children).containsAll(expectedChildren);
142+
children.removeAll(expectedChildren);
143+
assertThat(children).isEmpty();
144+
}
82145
}

backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/explorer/view/ExplorerViewControllerIntegrationTests.java

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@
6060
import org.eclipse.syson.application.data.GeneralViewEmptyTestProjectData;
6161
import org.eclipse.syson.application.data.ProjectWithLibraryDependencyContainingLibraryPackageTestProjectData;
6262
import org.eclipse.syson.application.data.WithUserLibrariesTestProjectData;
63+
import org.eclipse.syson.sysml.ConcernUsage;
6364
import org.eclipse.syson.sysml.ConstraintUsage;
6465
import org.eclipse.syson.sysml.Element;
66+
import org.eclipse.syson.sysml.FramedConcernMembership;
6567
import org.eclipse.syson.sysml.LibraryPackage;
6668
import org.eclipse.syson.sysml.Namespace;
6769
import org.eclipse.syson.sysml.RequirementConstraintMembership;
@@ -446,11 +448,11 @@ public void testCreateConstraintInRequirement() {
446448

447449
Runnable checkConstraintOwnership = () -> {
448450
var editingContextFunctionInput = new ExecuteEditingContextFunctionInput(UUID.randomUUID(), ExplorerViewDirectEditTestProjectData.EDITING_CONTEXT_ID, (editingContext, input) -> {
449-
var optionalContraint = this.objectSearchService.getObject(editingContext, newConstraintId.get());
450-
assertThat(optionalContraint).containsInstanceOf(ConstraintUsage.class);
451-
var constraint = (ConstraintUsage) optionalContraint.get();
451+
var optionalConstraint = this.objectSearchService.getObject(editingContext, newConstraintId.get());
452+
assertThat(optionalConstraint).containsInstanceOf(ConstraintUsage.class);
453+
var constraint = (ConstraintUsage) optionalConstraint.get();
452454
assertThat(constraint.getOwningRelationship()).isInstanceOf(RequirementConstraintMembership.class);
453-
return new ExecuteEditingContextFunctionSuccessPayload(input.id(), optionalContraint.get());
455+
return new ExecuteEditingContextFunctionSuccessPayload(input.id(), optionalConstraint.get());
454456
});
455457
Mono<IPayload> result = this.executeEditingContextFunctionRunner.execute(editingContextFunctionInput);
456458
var payload = result.block();
@@ -466,6 +468,55 @@ public void testCreateConstraintInRequirement() {
466468
.verify(Duration.ofSeconds(10));
467469
}
468470

471+
@DisplayName("GIVEN the Sirius Explorer View, WHEN creating a concern inside a requirement, THEN the new concern is owned through a FramedConcernMembership")
472+
@GivenSysONServer({ ExplorerViewDirectEditTestProjectData.SCRIPT_PATH })
473+
@Test
474+
public void testCreateConcernInRequirement() {
475+
var expandedIds = this.getAllTreeItemIds(ExplorerViewDirectEditTestProjectData.EDITING_CONTEXT_ID);
476+
var activatedFilters = List.of(SysONTreeFilterConstants.HIDE_ROOT_NAMESPACES_ID);
477+
var treeRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.sysONTreeViewDescriptionProvider.getDescriptionId(), expandedIds, activatedFilters);
478+
479+
var treeEventInput = new ExplorerEventInput(UUID.randomUUID(), ExplorerViewDirectEditTestProjectData.EDITING_CONTEXT_ID, treeRepresentationId);
480+
var treeFlux = this.treeEventSubscriptionRunner.run(treeEventInput).flux();
481+
482+
var newConcernId = new AtomicReference<String>(null);
483+
484+
Consumer<Object> ignorePayload = (o) -> {
485+
// Ignore the refresh event payload, we will check the actual semantic model content.
486+
};
487+
488+
Runnable createChildConstraint = () -> {
489+
var input = new CreateChildInput(UUID.randomUUID(), ExplorerViewDirectEditTestProjectData.EDITING_CONTEXT_ID, ExplorerViewDirectEditTestProjectData.SemanticIds.REQ1_RU_ID,
490+
"SysMLv2EditService-ConcernUsage");
491+
var result = this.createChildMutationRunner.run(input);
492+
String typename = JsonPath.read(result.data(), "$.data.createChild.__typename");
493+
assertThat(typename).isEqualTo(CreateChildSuccessPayload.class.getSimpleName());
494+
String objectId = JsonPath.read(result.data(), "$.data.createChild.object.id");
495+
newConcernId.set(objectId);
496+
};
497+
498+
Runnable checkConcernOwnership = () -> {
499+
var editingContextFunctionInput = new ExecuteEditingContextFunctionInput(UUID.randomUUID(), ExplorerViewDirectEditTestProjectData.EDITING_CONTEXT_ID, (editingContext, input) -> {
500+
var optionalConcern = this.objectSearchService.getObject(editingContext, newConcernId.get());
501+
assertThat(optionalConcern).containsInstanceOf(ConstraintUsage.class);
502+
var concern = (ConcernUsage) optionalConcern.get();
503+
assertThat(concern.getOwningRelationship()).isInstanceOf(FramedConcernMembership.class);
504+
return new ExecuteEditingContextFunctionSuccessPayload(input.id(), optionalConcern.get());
505+
});
506+
Mono<IPayload> result = this.executeEditingContextFunctionRunner.execute(editingContextFunctionInput);
507+
var payload = result.block();
508+
assertThat(payload).isInstanceOf(ExecuteEditingContextFunctionSuccessPayload.class);
509+
};
510+
511+
StepVerifier.create(treeFlux)
512+
.consumeNextWith(ignorePayload)
513+
.then(createChildConstraint)
514+
.consumeNextWith(ignorePayload)
515+
.then(checkConcernOwnership)
516+
.thenCancel()
517+
.verify(Duration.ofSeconds(10));
518+
}
519+
469520
private List<String> getAllTreeItemIds(String editingContextId) {
470521
ExecuteEditingContextFunctionInput executeEditingContextFunctionInput = new ExecuteEditingContextFunctionInput(UUID.randomUUID(), editingContextId, (editingContext, input) -> {
471522
if (editingContext instanceof IEMFEditingContext emfEditingContext) {

backend/services/syson-services/src/main/java/org/eclipse/syson/util/GetIntermediateContainerCreationSwitch.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.eclipse.emf.ecore.EClass;
1919
import org.eclipse.emf.ecore.EObject;
2020
import org.eclipse.syson.sysml.Comment;
21+
import org.eclipse.syson.sysml.ConcernUsage;
2122
import org.eclipse.syson.sysml.ConstraintUsage;
2223
import org.eclipse.syson.sysml.Definition;
2324
import org.eclipse.syson.sysml.Documentation;
@@ -70,6 +71,19 @@ public Optional<EClass> caseConstraintUsage(ConstraintUsage object) {
7071
return intermediateContainer;
7172
}
7273

74+
@Override
75+
public Optional<EClass> caseConcernUsage(ConcernUsage object) {
76+
Optional<EClass> intermediateContainer;
77+
if (this.container instanceof RequirementDefinition || this.container instanceof RequirementUsage) {
78+
// SysML v2 8.3.21.5: "A FramedConcernMembership is a RequirementConstraintMembership for a framed ConcernUsage of a
79+
// RequirementDefinition or RequirementUsage."
80+
intermediateContainer = Optional.of(SysmlPackage.eINSTANCE.getFramedConcernMembership());
81+
} else {
82+
intermediateContainer = this.caseFeature(object);
83+
}
84+
return intermediateContainer;
85+
}
86+
7387
@Override
7488
public Optional<EClass> caseDefinition(Definition object) {
7589
return Optional.of(SysmlPackage.eINSTANCE.getOwningMembership());

doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ a|image::explorer-expression-internals-hidden.png[Internals hidden (default)]
4343
a|image::explorer-expression-internals-visible.png[Internals visible]
4444
|===
4545

46+
** The dialog creating a child element provide two more options for `RequirementUsage` or `RequirementDefinition` tree items.
47+
One creates a `ConcernUsage` and another one creates `FramedConcernMembership`.
48+
The one creating a `ConcernUsage` create a `FramedConcernMembership` as an intermediate container.
49+
The one creating a `FramedConcernMembership` only creates the membership.
50+
In both cases, to display the `FramedConcernMembership` deactivate the `Hide Memberships` filter.
51+
4652
== Bug fixes
4753

4854
== Improvements

0 commit comments

Comments
 (0)