From 1e7daf6d0b3c3c5b1afecda78449bc1d677fed0a Mon Sep 17 00:00:00 2001 From: Guillaume Coutable Date: Thu, 21 May 2026 09:31:47 +0200 Subject: [PATCH 1/4] [2231] Add simple concern creation tool from Requirement Bug: https://github.com/eclipse-syson/syson/issues/2231 Signed-off-by: Guillaume Coutable --- CHANGELOG.adoc | 1 + .../common/view/services/ViewCreateService.java | 2 ++ .../view/SDVDescriptionNameGenerator.java | 5 ++++- .../view/SDVDiagramDescriptionProvider.java | 13 +++++++++++-- .../release-notes-framed-concern-tool.png | Bin 0 -> 50084 bytes .../pages/release-notes/2026.7.0.adoc | 4 ++++ 6 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 doc/content/modules/user-manual/assets/images/release-notes-framed-concern-tool.png diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 63db67bd6..1cc9ee216 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -24,6 +24,7 @@ - https://github.com/eclipse-syson/syson/issues/2116[#2116] [explorer] In the _Explorer_ view, the items corresponding to the internals of `Expression` elements (syntax tree) are now hidden by default. Disabling the _Hide expression internals_ filter in the _Explorer_ view allows to display them if needed. - https://github.com/eclipse-syson/syson/issues/2112[#2112] [diagrams] Add tools to create _Start_ and _Done_ `StateUsages`, available on `StateUsage` and `StateDefinition` graphical nodes. +- https://github.com/eclipse-syson/syson/issues/2231[#2231] [diagrams] Add a new tools to create a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. == v2026.5.0 diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java index 415a43bcb..8bb066b2e 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java @@ -213,6 +213,8 @@ private Membership createAppropriateMembership(EStructuralFeature feature) { ((RequirementConstraintMembership) result).setKind(RequirementConstraintKind.REQUIREMENT); } else if (feature.equals(SysmlPackage.eINSTANCE.getElement_Documentation())) { result = SysmlFactory.eINSTANCE.createOwningMembership(); + } else if (feature.equals(SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern()) || feature.equals(SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern())) { + result = SysmlFactory.eINSTANCE.createFramedConcernMembership(); } return result; } diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java index 7ba3058e0..98ab0ccde 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024, 2025 Obeo. + * Copyright (c) 2024, 2026 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -42,6 +42,9 @@ public String getCreationToolName(EReference eReference) { } else if (SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint().equals(eReference) || SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint().equals(eReference)) { name = "New Require constraint"; + } else if (SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern().equals(eReference) + || SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern().equals(eReference)) { + name = "New framed concern"; } return name; } diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java index c186afea7..d044a4bd0 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java @@ -229,8 +229,8 @@ public class SDVDiagramDescriptionProvider implements IRepresentationDescription Map.entry(SysmlPackage.eINSTANCE.getPerformActionUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedItem(), SysmlPackage.eINSTANCE.getUsage_NestedAction())), Map.entry(SysmlPackage.eINSTANCE.getPortDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAttribute(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort(), SysmlPackage.eINSTANCE.getDefinition_OwnedReference(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())), Map.entry(SysmlPackage.eINSTANCE.getPortUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getUsage_NestedReference(), SysmlPackage.eINSTANCE.getUsage_NestedPort(), SysmlPackage.eINSTANCE.getUsage_NestedItem())), - Map.entry(SysmlPackage.eINSTANCE.getRequirementDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getDefinition_OwnedRequirement(), SysmlPackage.eINSTANCE.getRequirementDefinition_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint())), - Map.entry(SysmlPackage.eINSTANCE.getRequirementUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint(), SysmlPackage.eINSTANCE.getUsage_NestedPort())), + Map.entry(SysmlPackage.eINSTANCE.getRequirementDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getDefinition_OwnedRequirement(), SysmlPackage.eINSTANCE.getRequirementDefinition_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern())), + Map.entry(SysmlPackage.eINSTANCE.getRequirementUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), SysmlPackage.eINSTANCE.getUsage_NestedPort())), Map.entry(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint(), SysmlPackage.eINSTANCE.getUsage_NestedPort())), Map.entry(SysmlPackage.eINSTANCE.getStateDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAction(), SysmlPackage.eINSTANCE.getDefinition_OwnedState())), Map.entry(SysmlPackage.eINSTANCE.getStateUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAction(), SysmlPackage.eINSTANCE.getUsage_NestedState())), @@ -636,6 +636,9 @@ private List> createCompartmentsForListIte } else if (SysmlPackage.eINSTANCE.getPortUsage().equals(eClass) && SysmlPackage.eINSTANCE.getUsage_NestedItem().equals(eReference)) { compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); compartmentNodeDescriptionProviders.add(new PortUsageNestedItemCompartmentItemNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); + } else if (SysmlPackage.eINSTANCE.getRequirementDefinition().equals(eClass) && SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern().equals(eReference) + || SysmlPackage.eINSTANCE.getRequirementUsage().equals(eClass) && SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern().equals(eReference)) { + compartmentNodeDescriptionProviders.add(new InheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); } else { compartmentNodeDescriptionProviders.add(new CompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); @@ -914,6 +917,9 @@ private List> createAllDefinitionOwnedUsag definitionOwnedUsageEdgeDescriptionProviders .add(new DefinitionOwnedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConstraintUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedConstraint(), colorProvider, this.getDescriptionNameGenerator())); + definitionOwnedUsageEdgeDescriptionProviders.add( + new DefinitionOwnedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedConcern(), colorProvider, + this.getDescriptionNameGenerator())); definitionOwnedUsageEdgeDescriptionProviders .add(new DefinitionOwnedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getInterfaceUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedInterface(), colorProvider, this.getDescriptionNameGenerator())); @@ -976,6 +982,9 @@ private List> createAllUsageCompositeEdgeD colorProvider, this.getDescriptionNameGenerator())); usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConstraint(), colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add( + new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConcern(), colorProvider, + this.getDescriptionNameGenerator())); usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), colorProvider, this.getDescriptionNameGenerator())); usageCompositeEdgeDescriptionProviders.add( diff --git a/doc/content/modules/user-manual/assets/images/release-notes-framed-concern-tool.png b/doc/content/modules/user-manual/assets/images/release-notes-framed-concern-tool.png new file mode 100644 index 0000000000000000000000000000000000000000..aaf269a36840acb66c615f8e3ee29f0ebd25c49a GIT binary patch literal 50084 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
3Ju=2(o|z?lQ=l|H>_#bo^CpMT>$~QuskU%w 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 z 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 CJfltk literal 0 HcmV?d00001 diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc index a4a1c1398..6f120fe65 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc @@ -19,6 +19,10 @@ image::release-notes-frame-edge.png[Frame edge between a RequirementUsage and a + image::release-notes-start-done-states.png[Tool to create a start and done, width=60%,height=60%] +** Add a new tools to create a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. ++ +image::release-notes-framed-concern-tool.png[Tool to create a _frame_ concern usage, width=60%,height=60%] + * In the _Explorer_ view: ** The tree items corresponding to the internals of `Expression` elements (syntax tree) are now hidden by default. From 64c07ed8dec7c12aac52c18ab18d20541a7c9c70 Mon Sep 17 00:00:00 2001 From: Guillaume Coutable Date: Tue, 5 May 2026 17:17:06 +0200 Subject: [PATCH 2/4] [2231] Add the support for frames compartments Bug: https://github.com/eclipse-syson/syson/issues/2231 Signed-off-by: Guillaume Coutable --- CHANGELOG.adoc | 1 + .../view/GVAddExistingElementsTests.java | 3 +- .../general/view/GVDropFromExplorerTests.java | 4 +- .../GVSubNodeRequirementCreationTests.java | 34 +++++++++- .../view/GVSubNodeStructureCreationTests.java | 4 +- .../general/view/GVTopNodeCreationTests.java | 4 +- .../general/view/GVViewUsageTests.java | 4 +- ...ConcernCompartmentItemNodeDescription.java | 54 ++++++++++++++++ ...amedConcernCompartmentNodeDescription.java | 61 ++++++++++++++++++ .../view/SDVDiagramDescriptionProvider.java | 39 ++++++++++- .../nodes/FakeNodeDescriptionProvider.java | 33 ++++++---- .../release-notes-frames-compartment.png | Bin 0 -> 46305 bytes .../pages/release-notes/2026.7.0.adoc | 4 ++ 13 files changed, 219 insertions(+), 26 deletions(-) create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentItemNodeDescription.java create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java create mode 100644 doc/content/modules/user-manual/assets/images/release-notes-frames-compartment.png diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 1cc9ee216..420e64d99 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -25,6 +25,7 @@ Disabling the _Hide expression internals_ filter in the _Explorer_ view allows to display them if needed. - https://github.com/eclipse-syson/syson/issues/2112[#2112] [diagrams] Add tools to create _Start_ and _Done_ `StateUsages`, available on `StateUsage` and `StateDefinition` graphical nodes. - https://github.com/eclipse-syson/syson/issues/2231[#2231] [diagrams] Add a new tools to create a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. +- 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. == v2026.5.0 diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVAddExistingElementsTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVAddExistingElementsTests.java index e4d2ffb80..b8f527c95 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVAddExistingElementsTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVAddExistingElementsTests.java @@ -147,6 +147,7 @@ public void addExistingElementsOnDiagram() { .verify(Duration.ofSeconds(10)); } + @DisplayName("GIVEN a GV diagram, WHEN adding existing element recursively, THEN expected nodes should have been added to the diagram") @GivenSysONServer({ GeneralViewAddExistingElementsTestProjectData.SCRIPT_PATH }) @Test public void addExistingElementsRecursiveOnDiagram() { @@ -450,7 +451,7 @@ private void checkRequirementUsage(Diagram newDiagram) { assertThat(optRequirementNode).isPresent(); assertThat(optRequirementNode.get().getChildNodes()) - .as("Node RequirementUsage should contain 8 hidden compartment children").hasSize(8) + .as("Node RequirementUsage should contain 9 hidden compartment children").hasSize(9) .allMatch(node -> node.getModifiers().contains(ViewModifier.Hidden)); } diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVDropFromExplorerTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVDropFromExplorerTests.java index c34f322be..f5af899d9 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVDropFromExplorerTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVDropFromExplorerTests.java @@ -237,12 +237,12 @@ public void dropFromExplorerShortNameOnlyOnEmptyDiagram() { new CheckDiagramElementCount(this.diagramComparator) .hasNewEdgeCount(0) // 1 node for the Requirement and 8 for its compartments and one for the documentation - .hasNewNodeCount(10) + .hasNewNodeCount(11) .check(diagram.get(), newDiagram); new CheckNodeOnDiagram(diagramDescriptionIdProvider, this.diagramComparator) .hasNodeDescriptionName(this.descriptionNameGenerator.getNodeName(SysmlPackage.eINSTANCE.getRequirementUsage())) .hasTargetObjectLabel("RequirementUsage") - .hasTotalCompartmentCount(8) + .hasTotalCompartmentCount(9) .check(diagram.get(), newDiagram); }); diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java index f39c2fd74..a075b4d54 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java @@ -123,7 +123,7 @@ private static Stream concernUsageSiblingNodeParameters() { return Stream.of( Arguments.of(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem(), 4), Arguments.of(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPart(), 11), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), 8)) + Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), 9)) .map(TestNameGenerator::namedArguments); } @@ -156,7 +156,7 @@ private static Stream concernDefinitionChildNodeParameters() { private static Stream concernDefinitionSiblingAndChildNodeParameters() { return Stream.of( - Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), "requirements", SysmlPackage.eINSTANCE.getDefinition_OwnedRequirement(), null, 10, 1), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), "requirements", SysmlPackage.eINSTANCE.getDefinition_OwnedRequirement(), null, 11, 1), Arguments.of(SysmlPackage.eINSTANCE.getConstraintUsage(), "assume constraints", SysmlPackage.eINSTANCE.getRequirementDefinition_AssumedConstraint(), "New Assume constraint", 6, 1), Arguments.of(SysmlPackage.eINSTANCE.getConstraintUsage(), "require constraints", SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint(), "New Require constraint", 6, 1)) .map(TestNameGenerator::namedArguments); @@ -210,7 +210,7 @@ private static Stream requirementUsageSiblingNodeParameters() { return Stream.of( Arguments.of(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem(), 4), Arguments.of(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPart(), 11), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), 8)) + Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), 9)) .map(TestNameGenerator::namedArguments); } @@ -797,6 +797,34 @@ public void createRequirementUsageSiblingNodes(EClass childEClass, EReference co Consumer diagramCheck = this.diagramCheckerService.siblingNodeGraphicalChecker(diagram, diagramDescriptionIdProvider, childEClass, compartmentCount); Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker("requirement", containmentReference, childEClass)); + StepVerifier.create(flux) + .consumeNextWith(initialDiagramContentConsumer) + .then(createNodeRunnable) + .consumeNextWith(diagramCheck) + .then(semanticCheck) + .thenCancel() + .verify(Duration.ofMinutes(10)); + } + + @DisplayName("GIVEN a Requirement Usage, WHEN creating a new framed concern, THEN a new framed concern is created") + @GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }) + @Test + public void createRequirementUsageFramedConcern() { + var flux = this.givenSubscriptionToDiagram(); + + AtomicReference diagram = new AtomicReference<>(); + Consumer initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set); + + var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, + SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID); + var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider); + + EClass parentEClass = SysmlPackage.eINSTANCE.getRequirementUsage(); + String targetObjectId = GeneralViewWithTopNodesTestProjectData.SemanticIds.REQUIREMENT_USAGE_ID; + Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId, "New framed concern"); + Consumer diagramCheck = this.diagramCheckerService.siblingNodeGraphicalChecker(diagram, diagramDescriptionIdProvider, SysmlPackage.eINSTANCE.getConcernUsage(), 8, 2); + Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker("requirement", SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), SysmlPackage.eINSTANCE.getConcernUsage())); + StepVerifier.create(flux) .consumeNextWith(initialDiagramContentConsumer) .then(createNodeRunnable) diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeStructureCreationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeStructureCreationTests.java index 82140fb1f..d9bb37e51 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeStructureCreationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeStructureCreationTests.java @@ -221,8 +221,8 @@ private static Stream packageChildNodeParameters() { Arguments.of(SysmlPackage.eINSTANCE.getPartUsage(), ownedMember, 11, 0, 0), Arguments.of(SysmlPackage.eINSTANCE.getPortDefinition(), ownedMember, 5, 0, 0), Arguments.of(SysmlPackage.eINSTANCE.getPortUsage(), ownedMember, 5, 0, 0), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementDefinition(), ownedMember, 8, 0, 0), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), ownedMember, 8, 0, 0), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementDefinition(), ownedMember, 9, 0, 0), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), ownedMember, 9, 0, 0), Arguments.of(SysmlPackage.eINSTANCE.getUseCaseDefinition(), ownedMember, 5, 0, 0), Arguments.of(SysmlPackage.eINSTANCE.getUseCaseUsage(), ownedMember, 7, 0, 0), Arguments.of(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), ownedMember, 8, 0, 0), diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java index 290e517c2..413aded8e 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java @@ -177,8 +177,8 @@ private static Stream topNodeParameters() { Arguments.of(SysmlPackage.eINSTANCE.getPortDefinition(), 5, 0, 0, 0, ViewConstants.DEFAULT_DEFINITION_NODE_HEIGHT, ViewConstants.DEFAULT_DEFINITION_NODE_WIDTH, false), Arguments.of(SysmlPackage.eINSTANCE.getPortUsage(), 5, 0, 0, 0, ViewConstants.DEFAULT_USAGE_NODE_HEIGHT, ViewConstants.DEFAULT_USAGE_NODE_WIDTH, false), Arguments.of(SysmlPackage.eINSTANCE.getReferenceUsage(), 0, 0, 0, 0, ViewConstants.DEFAULT_USAGE_NODE_HEIGHT, ViewConstants.DEFAULT_USAGE_NODE_WIDTH, false), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementDefinition(), 8, 0, 0, 0, ViewConstants.DEFAULT_DEFINITION_NODE_HEIGHT, ViewConstants.DEFAULT_DEFINITION_NODE_WIDTH, false), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), 8, 0, 0, 0, ViewConstants.DEFAULT_USAGE_NODE_HEIGHT, ViewConstants.DEFAULT_USAGE_NODE_WIDTH, false), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementDefinition(), 9, 0, 0, 0, ViewConstants.DEFAULT_DEFINITION_NODE_HEIGHT, ViewConstants.DEFAULT_DEFINITION_NODE_WIDTH, false), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), 9, 0, 0, 0, ViewConstants.DEFAULT_USAGE_NODE_HEIGHT, ViewConstants.DEFAULT_USAGE_NODE_WIDTH, false), Arguments.of(SysmlPackage.eINSTANCE.getUseCaseDefinition(), 5, 0, 0, 0, ViewConstants.DEFAULT_DEFINITION_NODE_HEIGHT, ViewConstants.DEFAULT_DEFINITION_NODE_WIDTH, false), Arguments.of(SysmlPackage.eINSTANCE.getUseCaseUsage(), 7, 0, 0, 0, ViewConstants.DEFAULT_USAGE_NODE_HEIGHT, ViewConstants.DEFAULT_USAGE_NODE_WIDTH, false), Arguments.of(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), 8, 0, 0, 0, ViewConstants.DEFAULT_USAGE_NODE_HEIGHT, ViewConstants.DEFAULT_USAGE_NODE_WIDTH, false), diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVViewUsageTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVViewUsageTests.java index 6f920fea9..f75b0ae73 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVViewUsageTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVViewUsageTests.java @@ -156,8 +156,8 @@ private static Stream childNodeParameters() { Arguments.of(SysmlPackage.eINSTANCE.getPartUsage(), 11, 0, 0, false), Arguments.of(SysmlPackage.eINSTANCE.getPortDefinition(), 5, 0, 0, false), Arguments.of(SysmlPackage.eINSTANCE.getPortUsage(), 5, 0, 0, false), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementDefinition(), 8, 0, 0, false), - Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), 8, 0, 0, false), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementDefinition(), 9, 0, 0, false), + Arguments.of(SysmlPackage.eINSTANCE.getRequirementUsage(), 9, 0, 0, false), Arguments.of(SysmlPackage.eINSTANCE.getUseCaseDefinition(), 5, 0, 0, false), Arguments.of(SysmlPackage.eINSTANCE.getUseCaseUsage(), 7, 0, 0, false), Arguments.of(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), 8, 0, 0, false), diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentItemNodeDescription.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentItemNodeDescription.java new file mode 100644 index 000000000..e2eacb9b8 --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentItemNodeDescription.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.syson.diagram.common.view.nodes; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.SysMLMetamodelHelper; + +/** + * Used to create a {@link org.eclipse.syson.sysml.ConcernUsage} compartment item node description. + *

+ * {@link org.eclipse.syson.sysml.ConcernUsage} compartment items have to be contained in a {@link org.eclipse.syson.sysml.FramedConcernMembership}. + *

+ * @author gcoutable + */ +public class FramedConcernCompartmentItemNodeDescription extends CompartmentItemNodeDescriptionProvider { + + public static final String COMPARTMENT_ITEM_NAME = " frame Concern"; + + public FramedConcernCompartmentItemNodeDescription(EClass eClass, EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(eClass, eReference, colorProvider, descriptionNameGenerator); + } + + @Override + public NodeDescription create() { + NodeDescription nodeDescription = super.create(); + nodeDescription.setPreconditionExpression("true"); + return nodeDescription; + } + + @Override + protected String getDomainType() { + return SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getElement()); + } + + @Override + protected String getName() { + return super.getName() + COMPARTMENT_ITEM_NAME; + } +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java new file mode 100644 index 000000000..955536cec --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.syson.diagram.common.view.nodes; + +import java.util.List; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.diagram.DiagramDescription; +import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.syson.util.IDescriptionNameGenerator; + +/** + * Compartment node allowing to display {@link org.eclipse.syson.sysml.ConcernUsage} owned by a {@link org.eclipse.syson.sysml.FramedConcernMembership}. + * + * @author gcoutable + */ +public class FramedConcernCompartmentNodeDescription extends AbstractCompartmentNodeDescriptionProvider { + + public static final String COMPARTMENT_NAME = " frames"; + + public FramedConcernCompartmentNodeDescription(EClass eClass, EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(eClass, eReference, colorProvider, descriptionNameGenerator); + } + + @Override + protected String getCompartmentName() { + return this.getDescriptionNameGenerator().getCompartmentName(this.eClass, this.eReference) + COMPARTMENT_NAME; + } + + @Override + protected String getCustomCompartmentLabel() { + return "frames"; + } + + @Override + public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { + cache.getNodeDescription(this.getDescriptionNameGenerator().getCompartmentName(this.eClass, this.eReference) + COMPARTMENT_NAME).ifPresent(nodeDescription -> { + cache.getNodeDescription(this.getDescriptionNameGenerator().getCompartmentItemName(this.eClass, this.eReference) + FramedConcernCompartmentItemNodeDescription.COMPARTMENT_ITEM_NAME) + .ifPresent(itemNodeDescription -> nodeDescription.getChildrenDescriptions().add(itemNodeDescription)); + nodeDescription.setPalette(this.createCompartmentPalette(cache)); + }); + } + + @Override + protected List getDroppableNodes(IViewDiagramElementFinder cache) { + return List.of(); + } +} diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java index d044a4bd0..6db904a61 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java @@ -52,6 +52,8 @@ import org.eclipse.syson.diagram.common.view.nodes.DoneActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ForkActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.FramedConcernCompartmentItemNodeDescription; +import org.eclipse.syson.diagram.common.view.nodes.FramedConcernCompartmentNodeDescription; import org.eclipse.syson.diagram.common.view.nodes.ImportedPackageNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.InheritedCompartmentItemNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.InterconnectionCompartmentNodeDescriptionProvider; @@ -382,6 +384,7 @@ public RepresentationDescription create(IColorProvider colorProvider) { this.linkActionPerformActionsCompartment(cache); this.linkInterconnectionCompartment(cache); this.linkSatisfyRequirementsCompartment(cache); + this.linkFramedConcernCompartment(cache); var palette = this.createDiagramPalette(cache); diagramDescription.setPalette(palette); @@ -545,11 +548,11 @@ private List> createAllCompartmentNodeDesc // ActionUsage, PartUsage, PerformActionUsage compartmentNodeDescriptionProviders.addAll(this.createCompartmentsForNestedAction(colorProvider)); - // Compartment "interconnection" (many usages and defintions) is defined for: + // Compartment "interconnection" (many usages and definitions) is defined for: // PartUsage, PartDefinition compartmentNodeDescriptionProviders.addAll(this.createInterconnectionCompartment(colorProvider)); - // Compartment "satisfy requirements" (many usages and defintions) is defined for: + // Compartment "satisfy requirements" (many usages and definitions) is defined for: // PartUsage, PartDefinition compartmentNodeDescriptionProviders.addAll(this.createSatisfyRequirementsCompartments(colorProvider)); @@ -578,6 +581,10 @@ private List> createAllCompartmentNodeDesc compartmentNodeDescriptionProviders.add(new StateTransitionCompartmentNodeDescriptionProvider(SysmlPackage.eINSTANCE.getExhibitStateUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState(), colorProvider, this.getDescriptionNameGenerator())); + // Compartment "frames" (ConcernUsage contained by FramedConcernMembership) is defined for: + // RequirementUsage, RequirementDefinition + compartmentNodeDescriptionProviders.addAll(this.createFramedConcernCompartments(colorProvider)); + compartmentNodeDescriptionProviders.addAll(this.createCompartmentsForListItems(colorProvider)); return compartmentNodeDescriptionProviders; @@ -710,6 +717,19 @@ private List> createSatisfyRequirementsCom return compartmentNodeDescriptionProviders; } + private List> createFramedConcernCompartments(IColorProvider colorProvider) { + List> compartmentNodeDescriptionProviders = new ArrayList<>(); + compartmentNodeDescriptionProviders.add(new FramedConcernCompartmentNodeDescription(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern(), + colorProvider, this.getDescriptionNameGenerator())); + compartmentNodeDescriptionProviders.add(new FramedConcernCompartmentItemNodeDescription(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern(), + colorProvider, this.getDescriptionNameGenerator())); + compartmentNodeDescriptionProviders.add(new FramedConcernCompartmentNodeDescription(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), + colorProvider, this.getDescriptionNameGenerator())); + compartmentNodeDescriptionProviders.add(new FramedConcernCompartmentItemNodeDescription(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), + colorProvider, this.getDescriptionNameGenerator())); + return compartmentNodeDescriptionProviders; + } + private List> createCompartmentsForConnectionEnd(IColorProvider colorProvider) { final List> compartmentNodeDescriptionProviders = new ArrayList<>(); @@ -1373,6 +1393,21 @@ private void linkSatisfyRequirementsCompartment(IViewDiagramElementFinder cache) })); } + private void linkFramedConcernCompartment(IViewDiagramElementFinder cache) { + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(SysmlPackage.eINSTANCE.getRequirementDefinition())) + .ifPresent(requirementDefinitionNodeDescription -> { + cache.getNodeDescription(this.descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern()) + + FramedConcernCompartmentNodeDescription.COMPARTMENT_NAME) + .ifPresent(requirementDefinitionNodeDescription.getReusedChildNodeDescriptions()::add); + }); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(SysmlPackage.eINSTANCE.getRequirementUsage())) + .ifPresent(requirementUsageNodeDescription -> { + cache.getNodeDescription(this.descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern()) + + FramedConcernCompartmentNodeDescription.COMPARTMENT_NAME) + .ifPresent(requirementUsageNodeDescription.getReusedChildNodeDescriptions()::add); + }); + } + private void addCompartmentNodeDescriptionInNodeDescription(IViewDiagramElementFinder cache, NodeDescription compartmentNodeDescription, EClass eClass) { cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(eClass)) .ifPresent(nodeDescription -> { diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java index d9c2dc08c..9f9125a70 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java @@ -19,6 +19,7 @@ import org.eclipse.sirius.components.view.builder.providers.IColorProvider; import org.eclipse.sirius.components.view.diagram.NodeDescription; import org.eclipse.syson.diagram.common.view.nodes.AbstractFakeNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.FramedConcernCompartmentNodeDescription; import org.eclipse.syson.diagram.common.view.nodes.InterconnectionCompartmentNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.SatisfyRequirementCompartmentNodeDescription; import org.eclipse.syson.diagram.common.view.nodes.StatesCompartmentNodeDescriptionProvider; @@ -59,18 +60,6 @@ protected List getChildrenDescription(IViewDiagramElementFinder private void addReusableCompartments(IViewDiagramElementFinder cache, IDescriptionNameGenerator descriptionNameGenerator, List childrenNodes) { // don't forget to add custom compartments - cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter())) - .ifPresent(childrenNodes::add); - cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter())) - .ifPresent(childrenNodes::add); - cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter())) - .ifPresent(childrenNodes::add); - cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_SubjectParameter())) - .ifPresent(childrenNodes::add); - cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_ActorParameter())) - .ifPresent(childrenNodes::add); - cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_StakeholderParameter())) - .ifPresent(childrenNodes::add); cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter())) .ifPresent(childrenNodes::add); cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter())) @@ -152,9 +141,29 @@ private void addReusableCompartments(IViewDiagramElementFinder cache, IDescripti cache.getNodeDescription(descriptionNameGenerator.getFreeFormCompartmentName(SysmlPackage.eINSTANCE.getExhibitStateUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState())) .ifPresent(childrenNodes::add); + this.addCustomCompartmentsForRequirements(cache, descriptionNameGenerator, childrenNodes); this.addCustomCompartmentsForParts(cache, descriptionNameGenerator, childrenNodes); } + private void addCustomCompartmentsForRequirements(IViewDiagramElementFinder cache, IDescriptionNameGenerator descriptionNameGenerator, List childrenNodes) { + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_SubjectParameter())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_ActorParameter())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_StakeholderParameter())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern()) + + FramedConcernCompartmentNodeDescription.COMPARTMENT_NAME).ifPresent(childrenNodes::add); + cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern()) + + FramedConcernCompartmentNodeDescription.COMPARTMENT_NAME).ifPresent(childrenNodes::add); + } + private void addCustomCompartmentsForParts(IViewDiagramElementFinder cache, IDescriptionNameGenerator descriptionNameGenerator, List childrenNodes) { cache.getNodeDescription(descriptionNameGenerator.getCompartmentName(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState()) + StatesCompartmentNodeDescriptionProvider.STATES_NAME) .ifPresent(childrenNodes::add); diff --git a/doc/content/modules/user-manual/assets/images/release-notes-frames-compartment.png b/doc/content/modules/user-manual/assets/images/release-notes-frames-compartment.png new file mode 100644 index 0000000000000000000000000000000000000000..67211493dcc31a31ea765336e7ef73f07b7287d1 GIT binary patch literal 46305 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 Jg@@1m@!$E|e+vKr literal 0 HcmV?d00001 diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc index 6f120fe65..583333fab 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc @@ -23,6 +23,10 @@ image::release-notes-start-done-states.png[Tool to create a start and done, widt + image::release-notes-framed-concern-tool.png[Tool to create a _frame_ concern usage, width=60%,height=60%] +** Add the _frames_ compartment graphical node in `RequirementUsage` and `RequirementDefinition` graphical nodes. ++ +image::release-notes-frames-compartment.png[frames compartment displaying concern usages of a requirement, width=60%,height=60%] + * In the _Explorer_ view: ** The tree items corresponding to the internals of `Expression` elements (syntax tree) are now hidden by default. From a0e1c749493b453d5987b7d329175af4fc08cb25 Mon Sep 17 00:00:00 2001 From: Guillaume Coutable Date: Thu, 21 May 2026 13:38:16 +0200 Subject: [PATCH 3/4] [2231] Fix checkstyle error Bug: https://github.com/eclipse-syson/syson/issues/2231 Signed-off-by: Guillaume Coutable --- .../view/SDVDiagramDescriptionProvider.java | 177 ++++++++++-------- 1 file changed, 94 insertions(+), 83 deletions(-) diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java index 6db904a61..36b3925d9 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java @@ -972,7 +972,75 @@ private List> createAllDefinitionOwnedUsag } private List> createAllUsageCompositeEdgeDescriptionProviders(IColorProvider colorProvider) { - final var usageCompositeEdgeDescriptionProviders = new ArrayList>(); + var usageCompositeEdgeDescriptionProviders = new ArrayList>(); + + usageCompositeEdgeDescriptionProviders.addAll(this.createAllUsageRequirementCompositeEdgeDescriptionProviders(colorProvider)); + usageCompositeEdgeDescriptionProviders.addAll(this.createAllUsageStructureCompositeEdgeDescriptionProviders(colorProvider)); + usageCompositeEdgeDescriptionProviders.addAll(this.createAllUsageBehaviorCompositeEdgeDescriptionProviders(colorProvider)); + usageCompositeEdgeDescriptionProviders.addAll(this.createAllUsageAnalysisCompositeEdgeDescriptionProviders(colorProvider)); + + return usageCompositeEdgeDescriptionProviders; + } + + private List> createAllUsageRequirementCompositeEdgeDescriptionProviders(IColorProvider colorProvider) { + var usageCompositeEdgeDescriptionProviders = new ArrayList>(); + + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConstraintUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConstraint(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConcern(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConstraint(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), + colorProvider, this.getDescriptionNameGenerator())); + + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + + usageCompositeEdgeDescriptionProviders.add(new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_StakeholderParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_StakeholderParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter(), + colorProvider, this.getDescriptionNameGenerator())); + + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + + return usageCompositeEdgeDescriptionProviders; + } + + private List> createAllUsageStructureCompositeEdgeDescriptionProviders(IColorProvider colorProvider) { + var usageCompositeEdgeDescriptionProviders = new ArrayList>(); + + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getAttributeUsage(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPart(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPort(), + colorProvider, this.getDescriptionNameGenerator())); + + return usageCompositeEdgeDescriptionProviders; + } + + private List> createAllUsageBehaviorCompositeEdgeDescriptionProviders(IColorProvider colorProvider) { + var usageCompositeEdgeDescriptionProviders = new ArrayList>(); usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getAcceptActionUsage(), SysmlPackage.eINSTANCE.getUsage_NestedAction(), colorProvider, this.getDescriptionNameGenerator())); @@ -980,97 +1048,40 @@ private List> createAllUsageCompositeEdgeD colorProvider, this.getDescriptionNameGenerator())); usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getAllocationUsage(), SysmlPackage.eINSTANCE.getUsage_NestedAllocation(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders - .add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getAttributeUsage(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConstraintUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConstraint(), + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getExhibitStateUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getExhibitStateUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem(), colorProvider, this.getDescriptionNameGenerator())); usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getOccurrenceUsage(), SysmlPackage.eINSTANCE.getUsage_NestedOccurrence(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPart(), colorProvider, this.getDescriptionNameGenerator())); usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getPerformActionUsage(), SysmlPackage.eINSTANCE.getUsage_NestedAction(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPort(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), + usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getStateUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConstraint(), - colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getUsage_NestedConcern(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add(new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getUsage_NestedRequirement(), - colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new UsageNestedUsageEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getStateUsage(), SysmlPackage.eINSTANCE.getUsage_NestedState(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_ActorParameter(), colorProvider, this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_ActorParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_ActorParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_ActorParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_ActorParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), colorProvider, - this.getDescriptionNameGenerator())); + return usageCompositeEdgeDescriptionProviders; + } - usageCompositeEdgeDescriptionProviders.add( - new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_StakeholderParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_StakeholderParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedStakeholderEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getConcernDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_StakeholderParameter(), colorProvider, - this.getDescriptionNameGenerator())); + private List> createAllUsageAnalysisCompositeEdgeDescriptionProviders(IColorProvider colorProvider) { + var usageCompositeEdgeDescriptionProviders = new ArrayList>(); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getIncludeUseCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getRequirementDefinition(), SysmlPackage.eINSTANCE.getRequirementDefinition_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); - usageCompositeEdgeDescriptionProviders.add( - new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_SubjectParameter(), colorProvider, - this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedActorEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_ActorParameter(), + colorProvider, this.getDescriptionNameGenerator())); + + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseDefinition(), SysmlPackage.eINSTANCE.getCaseDefinition_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getUseCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); + usageCompositeEdgeDescriptionProviders.add(new NestedSubjectEdgeDescriptionProvider(SysmlPackage.eINSTANCE.getIncludeUseCaseUsage(), SysmlPackage.eINSTANCE.getCaseUsage_SubjectParameter(), + colorProvider, this.getDescriptionNameGenerator())); return usageCompositeEdgeDescriptionProviders; } From 7bd39c1d5a91a7508b348c9b072b8afe4320577c Mon Sep 17 00:00:00 2001 From: Guillaume Coutable Date: Thu, 21 May 2026 16:43:34 +0200 Subject: [PATCH 4/4] [2235] Leverage the selection dialog to create framed concern usages Bug: https://github.com/eclipse-syson/syson/issues/2235 Signed-off-by: Guillaume Coutable --- CHANGELOG.adoc | 1 + .../GVSubNodeRequirementCreationTests.java | 82 +++++++++++++++- .../services/ModelMutationElementService.java | 13 ++- ...amedConcernCompartmentNodeDescription.java | 7 ++ .../common/view/services/ViewToolService.java | 30 ++++++ .../tools/FramedConcernNodeToolProvider.java | 98 +++++++++++++++++++ .../view/SDVDescriptionNameGenerator.java | 5 +- .../view/SDVDiagramDescriptionProvider.java | 7 +- .../services/SDVNodeToolSectionSwitch.java | 5 + .../pages/release-notes/2026.7.0.adoc | 2 + 10 files changed, 233 insertions(+), 17 deletions(-) create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/FramedConcernNodeToolProvider.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 420e64d99..798ba10e1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -26,6 +26,7 @@ Disabling the _Hide expression internals_ filter in the _Explorer_ view allows t - https://github.com/eclipse-syson/syson/issues/2112[#2112] [diagrams] Add tools to create _Start_ and _Done_ `StateUsages`, available on `StateUsage` and `StateDefinition` graphical nodes. - https://github.com/eclipse-syson/syson/issues/2231[#2231] [diagrams] Add a new tools to create a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. - 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. +- https://github.com/eclipse-syson/syson/issues/2235[#2235] [diagrams] Leverage the selection dialog to improve the node tool creating a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. == v2026.5.0 diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java index a075b4d54..f94dbc409 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeRequirementCreationTests.java @@ -30,6 +30,7 @@ import org.eclipse.emf.ecore.EReference; import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput; import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload; +import org.eclipse.sirius.components.core.api.IIdentityService; import org.eclipse.sirius.components.core.api.IObjectSearchService; import org.eclipse.sirius.components.diagrams.Diagram; import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider; @@ -44,6 +45,7 @@ import org.eclipse.syson.application.controllers.diagrams.testers.ToolTester; import org.eclipse.syson.application.controllers.utils.TestNameGenerator; import org.eclipse.syson.application.data.GeneralViewWithTopNodesTestProjectData; +import org.eclipse.syson.diagram.common.view.nodes.FramedConcernCompartmentItemNodeDescription; import org.eclipse.syson.services.SemanticRunnableFactory; import org.eclipse.syson.services.diagrams.DiagramComparator; import org.eclipse.syson.services.diagrams.DiagramDescriptionIdProvider; @@ -51,8 +53,11 @@ import org.eclipse.syson.services.diagrams.api.IGivenDiagramDescription; import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription; import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator; +import org.eclipse.syson.sysml.ConcernUsage; import org.eclipse.syson.sysml.Element; +import org.eclipse.syson.sysml.FramedConcernMembership; import org.eclipse.syson.sysml.PartUsage; +import org.eclipse.syson.sysml.ReferenceSubsetting; import org.eclipse.syson.sysml.ReferenceUsage; import org.eclipse.syson.sysml.Specialization; import org.eclipse.syson.sysml.Subsetting; @@ -111,6 +116,9 @@ public class GVSubNodeRequirementCreationTests extends AbstractIntegrationTests @Autowired private DiagramComparator diagramComparator; + @Autowired + private IIdentityService identityService; + private NodeCreationTestsService creationTestsService; private final IDescriptionNameGenerator descriptionNameGenerator = new SDVDescriptionNameGenerator(); @@ -806,10 +814,10 @@ public void createRequirementUsageSiblingNodes(EClass childEClass, EReference co .verify(Duration.ofMinutes(10)); } - @DisplayName("GIVEN a Requirement Usage, WHEN creating a new framed concern, THEN a new framed concern is created") + @DisplayName("GIVEN a Requirement Usage, WHEN creating a new framed concern without referencing another concern, THEN a new framed concern is created") @GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }) @Test - public void createRequirementUsageFramedConcern() { + public void createRequirementUsageFramedConcernWithoutSelection() { var flux = this.givenSubscriptionToDiagram(); AtomicReference diagram = new AtomicReference<>(); @@ -821,7 +829,7 @@ public void createRequirementUsageFramedConcern() { EClass parentEClass = SysmlPackage.eINSTANCE.getRequirementUsage(); String targetObjectId = GeneralViewWithTopNodesTestProjectData.SemanticIds.REQUIREMENT_USAGE_ID; - Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId, "New framed concern"); + Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithoutSelectionProvided(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId, "New framed concern"); Consumer diagramCheck = this.diagramCheckerService.siblingNodeGraphicalChecker(diagram, diagramDescriptionIdProvider, SysmlPackage.eINSTANCE.getConcernUsage(), 8, 2); Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker("requirement", SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), SysmlPackage.eINSTANCE.getConcernUsage())); @@ -834,6 +842,74 @@ public void createRequirementUsageFramedConcern() { .verify(Duration.ofSeconds(10)); } + @DisplayName("GIVEN a Requirement Usage, WHEN creating a new framed concern referencing another concern, THEN a new framed concern is created") + @GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }) + @Test + public void createRequirementUsageFramedConcernWithSelection() { + var flux = this.givenSubscriptionToDiagram(); + + AtomicReference diagram = new AtomicReference<>(); + Consumer initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set); + + var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, + SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID); + var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider); + + EClass parentEClass = SysmlPackage.eINSTANCE.getRequirementUsage(); + String targetObjectId = GeneralViewWithTopNodesTestProjectData.SemanticIds.REQUIREMENT_USAGE_ID; + Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId, "New framed concern", GeneralViewWithTopNodesTestProjectData.SemanticIds.CONCERN_USAGE_ID); + Consumer diagramCheck = assertRefreshedDiagramThat(newDiagram -> { + new CheckDiagramElementCount(this.diagramComparator) + .hasNewNodeCount(1) + .hasNewEdgeCount(1) + .check(diagram.get(), newDiagram); + + String newNodeDescriptionName = this.descriptionNameGenerator.getCompartmentItemName(SysmlPackage.eINSTANCE.getRequirementUsage(), SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern()) + FramedConcernCompartmentItemNodeDescription.COMPARTMENT_ITEM_NAME; + new CheckNodeInCompartment(diagramDescriptionIdProvider, this.diagramComparator) + .withTargetObjectId(targetObjectId) + .withCompartmentName("frames") + .hasNodeDescriptionName(newNodeDescriptionName) + .hasCompartmentCount(0) + .isHidden() + .check(diagram.get(), newDiagram); + }); + + Consumer additionalCheck = object -> { + assertThat(object).isInstanceOf(List.class) + .asInstanceOf(type(List.class)) + .satisfies(concernUsages -> { + assertThat((List) concernUsages).size().isEqualTo(1); + assertThat(concernUsages.getFirst()) + .isInstanceOf(ConcernUsage.class) + .asInstanceOf(type(ConcernUsage.class)) + .satisfies(concernUsage -> { + assertThat(concernUsage.eContainer()) + .isInstanceOf(FramedConcernMembership.class) + .asInstanceOf(type(FramedConcernMembership.class)) + .satisfies(framedConcernMembership -> { + assertThat(this.identityService.getId(framedConcernMembership.getReferencedConcern())).isEqualTo(GeneralViewWithTopNodesTestProjectData.SemanticIds.CONCERN_USAGE_ID); + assertThat(concernUsage.getOwnedRelationship().getFirst()) + .isInstanceOf(ReferenceSubsetting.class) + .asInstanceOf(type(ReferenceSubsetting.class)) + .satisfies(referenceSubsetting -> { + assertThat(referenceSubsetting.getReferencedFeature()).isEqualTo(framedConcernMembership.getReferencedConcern()); + }); + }); + }); + }); + }; + + Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(this.semanticCheckerService.getElementInParentSemanticChecker("requirement", SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), SysmlPackage.eINSTANCE.getConcernUsage(), additionalCheck)); + + StepVerifier.create(flux) + .consumeNextWith(initialDiagramContentConsumer) + .then(createNodeRunnable) + .consumeNextWith(diagramCheck) + .then(semanticCheck) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + @GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }) @ParameterizedTest @MethodSource("requirementUsageChildNodeParameters") diff --git a/backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/ModelMutationElementService.java b/backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/ModelMutationElementService.java index 34d03616c..e740334af 100644 --- a/backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/ModelMutationElementService.java +++ b/backend/services/syson-model-services/src/main/java/org/eclipse/syson/model/services/ModelMutationElementService.java @@ -220,13 +220,16 @@ public FramedConcernMembership createFramedConcern(Type type, ConcernUsage conce var newConcernUsage = SysmlFactory.eINSTANCE.createConcernUsage(); newFramedConcernMembership.getOwnedRelatedElement().add(newConcernUsage); - var newReferenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting(); - newConcernUsage.getOwnedRelationship().add(newReferenceSubsetting); - newReferenceSubsetting.setReferencedFeature(concernUsage); - this.metamodelMutationElementService.initialize(newFramedConcernMembership); this.metamodelMutationElementService.initialize(newConcernUsage); - this.metamodelMutationElementService.initialize(newReferenceSubsetting); + + if (concernUsage != null) { + var newReferenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting(); + newConcernUsage.getOwnedRelationship().add(newReferenceSubsetting); + newReferenceSubsetting.setReferencedFeature(concernUsage); + this.metamodelMutationElementService.initialize(newReferenceSubsetting); + } + return newFramedConcernMembership; } return null; diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java index 955536cec..b38f95b84 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/FramedConcernCompartmentNodeDescription.java @@ -18,8 +18,10 @@ import org.eclipse.emf.ecore.EReference; import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.builder.providers.INodeToolProvider; import org.eclipse.sirius.components.view.diagram.DiagramDescription; import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.syson.diagram.common.view.tools.FramedConcernNodeToolProvider; import org.eclipse.syson.util.IDescriptionNameGenerator; /** @@ -54,6 +56,11 @@ public void link(DiagramDescription diagramDescription, IViewDiagramElementFinde }); } + @Override + protected List getItemCreationToolProviders() { + return List.of(new FramedConcernNodeToolProvider()); + } + @Override protected List getDroppableNodes(IViewDiagramElementFinder cache) { return List.of(); diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewToolService.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewToolService.java index fb39b78dc..a12bbf760 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewToolService.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewToolService.java @@ -588,6 +588,36 @@ public List getExhibitStateSelectionDialogChildren(Object sele return this.getChildrenWithInstancesOf(selectionDialogTreeElement, editingContext, expandedIds, List.of(SysmlPackage.eINSTANCE.getStateUsage())); } + /** + * Provides the root elements in the tree of the selection dialog for presenting all existing ConcernUsage. + * + * @param editingContext + * the (non-{@code null}) {@link IEditingContext}. + * @return the (non-{@code null}) {@link List} of all {@link Resource} and {@link ISysONExplorerFragment} that + * contain at least one {@link org.eclipse.syson.sysml.ConcernUsage}. + */ + public List getConcernReferenceSelectionDialogElements(IEditingContext editingContext) { + return this.getAllResourcesWithInstancesOf(editingContext, List.of(SysmlPackage.eINSTANCE.getConcernUsage())); + } + + /** + * Provides the children of element in the tree of the selection dialog for presenting all existing ConcernUsage. + * + * @param selectionDialogTreeElement + * a (non-{@code null}) selection dialog tree element. + * @param editingContext + * the (non-{@code null}) {@link IEditingContext}. + * @param expandedIds + * the list of already expanded treeItems, by their Ids. + * @return the (non-{@code null}) {@link List} of all children that contain (possibly indirectly) an + * {@link org.eclipse.syson.sysml.ConcernUsage}. + */ + public List getConcernReferenceSelectionDialogChildren(Object selectionDialogTreeElement, IEditingContext editingContext, List expandedIds) { + return this.getChildrenWithInstancesOf(selectionDialogTreeElement, editingContext, expandedIds, List.of(SysmlPackage.eINSTANCE.getConcernUsage())); + } + + + /** * Provides the root elements in the tree of the selection dialog for the any creation tool. * diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/FramedConcernNodeToolProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/FramedConcernNodeToolProvider.java new file mode 100644 index 000000000..44cd31fe6 --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/FramedConcernNodeToolProvider.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.syson.diagram.common.view.tools; + +import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.diagrams.Node; +import org.eclipse.sirius.components.trees.renderer.TreeRenderer; +import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.generated.diagram.DiagramBuilders; +import org.eclipse.sirius.components.view.builder.generated.view.ViewBuilders; +import org.eclipse.sirius.components.view.builder.providers.INodeToolProvider; +import org.eclipse.sirius.components.view.diagram.DialogDescription; +import org.eclipse.sirius.components.view.diagram.NodeTool; +import org.eclipse.sirius.components.view.emf.diagram.ViewDiagramDescriptionConverter; +import org.eclipse.syson.diagram.common.view.services.ViewToolService; +import org.eclipse.syson.diagram.services.aql.DiagramMutationAQLService; +import org.eclipse.syson.model.services.aql.ModelMutationAQLService; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.ServiceMethod; +import org.eclipse.syson.util.SysMLMetamodelHelper; + +/** + * Used to create a framed {@link org.eclipse.syson.sysml.ConcernUsage} in a {@link org.eclipse.syson.sysml.RequirementUsage} or a {@link org.eclipse.syson.sysml.RequirementDefinition}. + * + * @author gcoutable + */ +public class FramedConcernNodeToolProvider implements INodeToolProvider { + + private final DiagramBuilders diagramBuilderHelper = new DiagramBuilders(); + + private final ViewBuilders viewBuilderHelper = new ViewBuilders(); + + @Override + public NodeTool create(IViewDiagramElementFinder cache) { + var builder = this.diagramBuilderHelper.newNodeTool(); + + var updateExposedElements = this.viewBuilderHelper.newChangeContext() + .expression(ServiceMethod.of4(DiagramMutationAQLService::expose).aqlSelf(IEditingContext.EDITING_CONTEXT, DiagramContext.DIAGRAM_CONTEXT, Node.SELECTED_NODE, + ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE)); + + var selectedElementToExpose = this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL_SELF + ".referencedConcern") + .children(updateExposedElements.build()); + + var body = this.viewBuilderHelper.newChangeContext() + .expression(ServiceMethod.of1(ModelMutationAQLService::createFramedConcern).aqlSelf("selectedObject")) + .children(selectedElementToExpose.build()); + + return builder + .name(this.getToolName()) + .iconURLsExpression("/icons/full/obj16/ConcernUsage.svg") + .body(body.build()) + .dialogDescription(this.getSelectionDialogDescription()) + .build(); + } + + private String getToolName() { + return "New framed concern"; + } + + private DialogDescription getSelectionDialogDescription() { + String concernUsageType = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getConcernUsage()); + + var selectionDialogTree = this.diagramBuilderHelper.newSelectionDialogTreeDescription() + .isSelectableExpression(AQLConstants.AQL_SELF + ".oclIsKindOf(" + concernUsageType + ")") + .elementsExpression(ServiceMethod.of0(ViewToolService::getConcernReferenceSelectionDialogElements).aql(IEditingContext.EDITING_CONTEXT)) + .childrenExpression(ServiceMethod.of2(ViewToolService::getConcernReferenceSelectionDialogChildren).aqlSelf(IEditingContext.EDITING_CONTEXT, TreeRenderer.EXPANDED)) + .build(); + + return this.diagramBuilderHelper.newSelectionDialogDescription() + .selectionDialogTreeDescription(selectionDialogTree) + .defaultTitleExpression(this.getToolName()) + .noSelectionTitleExpression(this.getToolName()) + .withSelectionTitleExpression(this.getToolName()) + .descriptionExpression("Create a framed Concern") + .noSelectionActionLabelExpression("Create a new framed Concern") + .noSelectionActionDescriptionExpression("Create a new framed Concern without referencing an existing Concern") + .withSelectionActionLabelExpression("Select an existing Concern to frame") + .withSelectionActionDescriptionExpression("Create a new framed Concern referencing the selected Concern") + .noSelectionActionStatusMessageExpression("It will create a new framed Concern without referencing an existing Concern") + .selectionRequiredWithoutSelectionStatusMessageExpression("Select on Concern to frame") + .selectionRequiredWithSelectionStatusMessageExpression(AQLConstants.AQL + "'It will create a new Concern referencing ' + selectedObjects->first().name") + .optional(true) + .build(); + } +} diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java index 98ab0ccde..7ba3058e0 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDescriptionNameGenerator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024, 2026 Obeo. + * Copyright (c) 2024, 2025 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -42,9 +42,6 @@ public String getCreationToolName(EReference eReference) { } else if (SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint().equals(eReference) || SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint().equals(eReference)) { name = "New Require constraint"; - } else if (SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern().equals(eReference) - || SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern().equals(eReference)) { - name = "New framed concern"; } return name; } diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java index 36b3925d9..1f635f48d 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/SDVDiagramDescriptionProvider.java @@ -231,8 +231,8 @@ public class SDVDiagramDescriptionProvider implements IRepresentationDescription Map.entry(SysmlPackage.eINSTANCE.getPerformActionUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedItem(), SysmlPackage.eINSTANCE.getUsage_NestedAction())), Map.entry(SysmlPackage.eINSTANCE.getPortDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAttribute(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort(), SysmlPackage.eINSTANCE.getDefinition_OwnedReference(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())), Map.entry(SysmlPackage.eINSTANCE.getPortUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getUsage_NestedReference(), SysmlPackage.eINSTANCE.getUsage_NestedPort(), SysmlPackage.eINSTANCE.getUsage_NestedItem())), - Map.entry(SysmlPackage.eINSTANCE.getRequirementDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getDefinition_OwnedRequirement(), SysmlPackage.eINSTANCE.getRequirementDefinition_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint(), SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern())), - Map.entry(SysmlPackage.eINSTANCE.getRequirementUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern(), SysmlPackage.eINSTANCE.getUsage_NestedPort())), + Map.entry(SysmlPackage.eINSTANCE.getRequirementDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getDefinition_OwnedRequirement(), SysmlPackage.eINSTANCE.getRequirementDefinition_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint())), + Map.entry(SysmlPackage.eINSTANCE.getRequirementUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_ActorParameter(), SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint(), SysmlPackage.eINSTANCE.getUsage_NestedPort())), Map.entry(SysmlPackage.eINSTANCE.getSatisfyRequirementUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAttribute(), SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint(), SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint(), SysmlPackage.eINSTANCE.getUsage_NestedPort())), Map.entry(SysmlPackage.eINSTANCE.getStateDefinition(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getDefinition_OwnedAction(), SysmlPackage.eINSTANCE.getDefinition_OwnedState())), Map.entry(SysmlPackage.eINSTANCE.getStateUsage(), List.of(SysmlPackage.eINSTANCE.getElement_Documentation(), SysmlPackage.eINSTANCE.getUsage_NestedAction(), SysmlPackage.eINSTANCE.getUsage_NestedState())), @@ -643,9 +643,6 @@ private List> createCompartmentsForListIte } else if (SysmlPackage.eINSTANCE.getPortUsage().equals(eClass) && SysmlPackage.eINSTANCE.getUsage_NestedItem().equals(eReference)) { compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); compartmentNodeDescriptionProviders.add(new PortUsageNestedItemCompartmentItemNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); - } else if (SysmlPackage.eINSTANCE.getRequirementDefinition().equals(eClass) && SysmlPackage.eINSTANCE.getRequirementDefinition_FramedConcern().equals(eReference) - || SysmlPackage.eINSTANCE.getRequirementUsage().equals(eClass) && SysmlPackage.eINSTANCE.getRequirementUsage_FramedConcern().equals(eReference)) { - compartmentNodeDescriptionProviders.add(new InheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); } else { compartmentNodeDescriptionProviders.add(new CompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java index 4d13515ec..b44f8f24c 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java @@ -37,6 +37,7 @@ import org.eclipse.syson.diagram.common.view.tools.DoneStateNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.ExhibitStateNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.ForkActionNodeToolProvider; +import org.eclipse.syson.diagram.common.view.tools.FramedConcernNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.InterfaceDefinitionEndCompartmentNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.JoinActionNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.MergeActionNodeToolProvider; @@ -698,6 +699,8 @@ public List caseRequirementUsage(RequirementUsage object) { this.toolDescriptionService.createNodeTool(this.getNodeDescription(SysmlPackage.eINSTANCE.getPartUsage()), SysmlPackage.eINSTANCE.getPartUsage())); this.toolDescriptionService.addNodeTool(sections, ToolConstants.REQUIREMENTS, this.toolDescriptionService.createNodeTool(this.getNodeDescription(SysmlPackage.eINSTANCE.getRequirementUsage()), SysmlPackage.eINSTANCE.getRequirementUsage())); + this.toolDescriptionService.addNodeTool(sections, ToolConstants.REQUIREMENTS, + new FramedConcernNodeToolProvider().create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.STRUCTURE, this.createNewSubjectNodeTool()); this.toolDescriptionService.addNodeTool(sections, ToolConstants.STRUCTURE, this.createNewActorNodeTool()); this.toolDescriptionService.addNodeTool(sections, ToolConstants.STRUCTURE, this.createNewStakeholderNodeTool()); @@ -718,6 +721,8 @@ public List caseRequirementUsage(RequirementUsage object) { @Override public List caseRequirementDefinition(RequirementDefinition object) { var sections = this.toolDescriptionService.createDefaultNodeToolSections(); + this.toolDescriptionService.addNodeTool(sections, ToolConstants.REQUIREMENTS, + new FramedConcernNodeToolProvider().create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.STRUCTURE, this.createNewSubjectNodeTool()); this.toolDescriptionService.addNodeTool(sections, ToolConstants.STRUCTURE, this.createNewActorNodeTool()); this.toolDescriptionService.addNodeTool(sections, ToolConstants.STRUCTURE, this.createNewStakeholderNodeTool()); diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc index 583333fab..ef1a6ca9e 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.7.0.adoc @@ -27,6 +27,8 @@ image::release-notes-framed-concern-tool.png[Tool to create a _frame_ concern us + image::release-notes-frames-compartment.png[frames compartment displaying concern usages of a requirement, width=60%,height=60%] +** Leverage the selection dialog to improve the node tool creating a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. + * In the _Explorer_ view: ** The tree items corresponding to the internals of `Expression` elements (syntax tree) are now hidden by default.