diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 24f687b01..9eb07b831 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -115,9 +115,10 @@ The edge goes from the derived requirement to the original one and is displayed - https://github.com/eclipse-syson/syson/issues/2428[#2428] [diagrams] Add the _New Derived Requirement_ edge tool on `RequirementUsage` graphical nodes, creating a requirement derivation towards another `RequirementUsage`. The edge is drawn from the derived requirement to the original one, and the created derivation has the same shape as one written in text: a `ConnectionUsage` annotated with `#derivation`, whose ends are annotated with `#original` and `#derive`. The import of the `RequirementDerivation` library is added to the owning namespace when it is missing. -- https://github.com/eclipse-syson/syson/issues/2470[#2470] [diagrams] Add the selection of an existing element in `New ItemDefinition as Payload` and `New PartDefinition as Payload` tools on `AcceptAction` graphical node. +- https://github.com/eclipse-syson/syson/issues/2470[#2470] [diagrams] Add the selection of an existing `Element` in _New ItemDefinition as Payload_ and _New PartDefinition as Payload_ tools on `AcceptAction` graphical nodes. +- https://github.com/eclipse-syson/syson/issues/2471[#2471] [diagrams] Add the selection of an existing `PortUsage` in `New Port as Receiver` tool on `AcceptAction` graphical node. + -== v20 == v2026.7.0 === Breaking changes diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeActionFlowCreationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeActionFlowCreationTests.java index 9cba57254..18d367f7c 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeActionFlowCreationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVSubNodeActionFlowCreationTests.java @@ -135,6 +135,13 @@ private static Stream acceptActionUsagePayloadParameters() { ); } + private static Stream acceptActionUsageReceiverParameters() { + return Stream.of( + Arguments.of(""), + Arguments.of(GeneralViewWithTopNodesTestProjectData.SemanticIds.PORT_USAGE_ID) + ); + } + private static Stream actionUsageSiblingNodeParameters() { return Stream.of( Arguments.of(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPart(), 13)) @@ -297,10 +304,21 @@ public void createAcceptActionUsagePayload(EClass eClass, String selectedNodeId) } @GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }) - @Test - public void createAcceptActionUsageReceiver() { + @MethodSource("acceptActionUsageReceiverParameters") + @ParameterizedTest + public void createAcceptActionUsageReceiver(String selectedObjectId) { var flux = this.givenSubscriptionToDiagram(); + AtomicReference expectedReceiverName = new AtomicReference<>(); + ISemanticChecker initialSemanticChecker = (editingContext) -> { + expectedReceiverName.set(this.objectSearchService.getObject(editingContext, selectedObjectId) + .filter(Element.class::isInstance) + .map(Element.class::cast) + .map(Element::getDeclaredName) + .orElse("acceptActionReceiver")); + }; + Runnable initialSemanticCheck = this.semanticCheckerService.checkEditingContext(initialSemanticChecker); + var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID); var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider); @@ -312,8 +330,8 @@ public void createAcceptActionUsageReceiver() { AtomicReference diagram = new AtomicReference<>(); Consumer initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set); - Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId, - this.descriptionNameGenerator.getCreationToolName("New {0} as Receiver", eClass)); + Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId, + this.descriptionNameGenerator.getCreationToolName("New {0} as Receiver", eClass), selectedObjectId); Consumer diagramCheck = assertRefreshedDiagramThat(newDiagram -> { new CheckDiagramElementCount(this.diagramComparator) @@ -327,7 +345,7 @@ public void createAcceptActionUsageReceiver() { assertThat(updatedNode.getInsideLabel()).as("The updated node label should exist").isNotNull(); assertThat(updatedNode.getInsideLabel().getText()) .contains(LabelConstants.OPEN_QUOTE + "via" + LabelConstants.CLOSE_QUOTE) - .contains("acceptAction's receiver"); + .contains(expectedReceiverName.get()); }); ISemanticChecker semanticChecker = (editingContext) -> { @@ -345,13 +363,14 @@ public void createAcceptActionUsageReceiver() { assertThat(relationship).isInstanceOf(Membership.class); Membership membership = (Membership) relationship; assertThat(eClass.isInstance(membership.getMemberElement())).isTrue(); - assertThat(membership.getMemberElement().getName()).isEqualTo("acceptAction's receiver"); + assertThat(membership.getMemberElement().getName()).isEqualTo(expectedReceiverName.get()); }; Runnable semanticCheck = this.semanticCheckerService.checkEditingContext(semanticChecker); StepVerifier.create(flux) .consumeNextWith(initialDiagramContentConsumer) + .then(initialSemanticCheck) .then(createNodeRunnable) .consumeNextWith(diagramCheck) .then(semanticCheck) diff --git a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramMutationToolService.java b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramMutationToolService.java index 21eabd0d3..60501d538 100644 --- a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramMutationToolService.java +++ b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramMutationToolService.java @@ -57,6 +57,7 @@ import org.eclipse.syson.sysml.PartDefinition; import org.eclipse.syson.sysml.PartUsage; import org.eclipse.syson.sysml.PerformActionUsage; +import org.eclipse.syson.sysml.PortUsage; import org.eclipse.syson.sysml.ReferenceUsage; import org.eclipse.syson.sysml.RequirementConstraintKind; import org.eclipse.syson.sysml.RequirementConstraintMembership; @@ -657,23 +658,20 @@ private Type createNewAcceptActionPayload(String payloadEClassName, AcceptAction * Create or replace the receiver parameter of an accept action usage. * * @param self - * the accept action usage + * the accept action usage + * @param selectedObject + * the existing port given by the selection dialog. Can be null. * @return the given accept action usage */ - public Element createAcceptActionReceiver(AcceptActionUsage self) { - var newPort = SysmlFactory.eINSTANCE.createPortUsage(); - newPort.setDeclaredName(self.getDeclaredName() + "'s receiver"); - var owningMembership = SysmlFactory.eINSTANCE.createOwningMembership(); - owningMembership.getOwnedRelatedElement().add(newPort); - var receiverParent = this.getClosestContainingPackageFrom(self); - receiverParent.getOwnedRelationship().add(owningMembership); - + public Element createAcceptActionReceiver(AcceptActionUsage self, PortUsage selectedObject) { + var portReceiver = Optional.ofNullable(selectedObject) + .orElseGet(() -> this.createNewAcceptActionReceiver(self)); var feature = SysmlFactory.eINSTANCE.createFeature(); feature.setDirection(FeatureDirectionKind.OUT); var returnParameterMembership = SysmlFactory.eINSTANCE.createReturnParameterMembership(); returnParameterMembership.getOwnedRelatedElement().add(feature); var membership = SysmlFactory.eINSTANCE.createMembership(); - membership.setMemberElement(newPort); + membership.setMemberElement(portReceiver); var featureReferenceExpression = SysmlFactory.eINSTANCE.createFeatureReferenceExpression(); featureReferenceExpression.getOwnedRelationship().add(membership); featureReferenceExpression.getOwnedRelationship().add(returnParameterMembership); @@ -694,6 +692,23 @@ public Element createAcceptActionReceiver(AcceptActionUsage self) { return self; } + /** + * Creates a new receiver {@link PortUsage} to set in the given {@link AcceptActionUsage}. + * + * @param self + * the accept action in which the new receiver should be set. + * @return the newly created receiver {@link PortUsage}. + */ + private PortUsage createNewAcceptActionReceiver(AcceptActionUsage self) { + var newPort = SysmlFactory.eINSTANCE.createPortUsage(); + newPort.setDeclaredName(self.getDeclaredName() + "Receiver"); + var owningMembership = SysmlFactory.eINSTANCE.createOwningMembership(); + owningMembership.getOwnedRelatedElement().add(newPort); + var receiverParent = this.getClosestContainingPackageFrom(self); + receiverParent.getOwnedRelationship().add(owningMembership); + return newPort; + } + /** * Add the standard start action as the child of the given element. * diff --git a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/aql/DiagramMutationAQLService.java b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/aql/DiagramMutationAQLService.java index 4bac75bf2..dd4e1c9a9 100644 --- a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/aql/DiagramMutationAQLService.java +++ b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/aql/DiagramMutationAQLService.java @@ -151,10 +151,10 @@ public Element createAcceptActionPayload(AcceptActionUsage self, String payloadE } /** - * {@link DiagramMutationToolService#createAcceptActionReceiver(AcceptActionUsage)}. + * {@link DiagramMutationToolService#createAcceptActionReceiver(AcceptActionUsage, PortUsage)}. */ - public Element createAcceptActionReceiver(AcceptActionUsage self) { - return this.diagramMutationToolService.createAcceptActionReceiver(self); + public Element createAcceptActionReceiver(AcceptActionUsage self, PortUsage selectedObject) { + return this.diagramMutationToolService.createAcceptActionReceiver(self, selectedObject); } /** diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/AcceptActionPortUsageReceiverToolNodeProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/AcceptActionPortUsageReceiverToolNodeProvider.java index 7599c5033..8a8264f3f 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/AcceptActionPortUsageReceiverToolNodeProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/AcceptActionPortUsageReceiverToolNodeProvider.java @@ -12,17 +12,25 @@ *******************************************************************************/ package org.eclipse.syson.diagram.common.view.tools; +import java.util.List; + +import org.eclipse.sirius.components.core.api.IEditingContext; +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.syson.diagram.services.aql.DiagramMutationAQLService; import org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService; import org.eclipse.syson.sysml.PortUsage; import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.tree.services.aql.TreeQueryAQLService; import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.AQLUtils; import org.eclipse.syson.util.ServiceMethod; +import org.eclipse.syson.util.SysMLMetamodelHelper; /** * Used to create a {@link PortUsage} as the receiver of an accept action usage. @@ -40,7 +48,7 @@ public NodeTool create(IViewDiagramElementFinder cache) { var builder = this.diagramBuilderHelper.newNodeTool(); var creationPayloadServiceCall = this.viewBuilderHelper.newChangeContext() - .expression(ServiceMethod.of0(DiagramMutationAQLService::createAcceptActionReceiver).aqlSelf()) + .expression(ServiceMethod.of1(DiagramMutationAQLService::createAcceptActionReceiver).aqlSelf("selectedObject")) .build(); var rootChangContext = this.viewBuilderHelper.newChangeContext() @@ -52,6 +60,31 @@ public NodeTool create(IViewDiagramElementFinder cache) { .iconURLsExpression("/icons/full/obj16/" + SysmlPackage.eINSTANCE.getPortUsage().getName() + ".svg") .body(rootChangContext) .preconditionExpression(ServiceMethod.of0(DiagramQueryAQLService::isEmptyAcceptActionUsageReceiver).aqlSelf()) + .dialogDescription(this.getSelectionDialogDescription()) + .build(); + } + + private DialogDescription getSelectionDialogDescription() { + var receiverTypeName = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getPortUsage()); + var selectionDialogTree = this.diagramBuilderHelper.newSelectionDialogTreeDescription() + .elementsExpression(ServiceMethod.of1(TreeQueryAQLService::getSelectionDialogElements).aql(IEditingContext.EDITING_CONTEXT, AQLUtils.aqlSequence(List.of(receiverTypeName)))) + .childrenExpression( + ServiceMethod.of3(TreeQueryAQLService::getSelectionDialogChildren).aqlSelf(IEditingContext.EDITING_CONTEXT, TreeRenderer.EXPANDED, AQLUtils.aqlSequence(List.of(receiverTypeName)))) + .isSelectableExpression(AQLConstants.AQL_SELF + ".oclIsKindOf(" + receiverTypeName + ")") + .build(); + String receiverName = SysmlPackage.eINSTANCE.getPortUsage().getName(); + return this.diagramBuilderHelper.newSelectionDialogDescription() + .selectionDialogTreeDescription(selectionDialogTree) + .defaultTitleExpression("Set the receiver") + .descriptionExpression(receiverName + " as receiver") + .noSelectionActionLabelExpression("Create a New " + receiverName) + .noSelectionActionDescriptionExpression("Set the receiver with a New " + receiverName) + .withSelectionActionLabelExpression("Select an existing " + receiverName) + .withSelectionActionDescriptionExpression("Set the receiver with an existing " + receiverName) + .noSelectionActionStatusMessageExpression("It will set the receiver with a New " + receiverName) + .selectionRequiredWithoutSelectionStatusMessageExpression("Select one " + receiverName) + .selectionRequiredWithSelectionStatusMessageExpression(AQLConstants.AQL + "'It will set the receiver with ' + selectedObjects->first().name") + .optional(true) .build(); } } diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc index 45a4354f8..48b5ba5d6 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.9.0.adoc @@ -95,9 +95,10 @@ image::release-notes-action-inherited-item-border-nodes.png[ItemUsage border nod ** Add support for the inheritance of `ItemUsage` border nodes on `PortDefinition` and `PortUsage` graphical nodes. + image::release-notes-port-inherited-item-border-nodes.png[ItemUsage border node inheritance on PortDefinition and PortUsage, width=80%,height=80%] -** Add the capability of selecting an existing `ItemDefinition` in _New ItemDefinition as Payload_ and _New PartDefinition as Payload_ tools on `AcceptAction` graphical nodes. -The creation of a new `ItemDefinition` remains available. - +** Add the capability of selecting an existing `Element` in _New ItemDefinition as Payload_ and _New PartDefinition as Payload_ tools on `AcceptAction` graphical nodes. +The creation of a new `Element` remains available. +** Add the capability of selecting an existing `PortUsage` in _New Port as Receiver_ tool on `AcceptAction` graphical nodes. +The creation of a new `PortUsage` remains available. == Bug fixes * In diagrams: