Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ 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/2471[#2471] [diagrams] Add the selection of an existing `PortUsage` in `New Port as Receiver` tool on `AcceptAction` graphical node.

== v20
== v2026.7.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ private static Stream<Arguments> acceptActionUsagePayloadParameters() {
.map(TestNameGenerator::namedArguments);
}

private static Stream<Arguments> acceptActionUsageReceiverParameters() {
return Stream.of(
Arguments.of(""),
Arguments.of(GeneralViewWithTopNodesTestProjectData.SemanticIds.PORT_USAGE_ID)
);
}

private static Stream<Arguments> actionUsageSiblingNodeParameters() {
return Stream.of(
Arguments.of(SysmlPackage.eINSTANCE.getPartUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPart(), 13))
Expand Down Expand Up @@ -284,10 +291,21 @@ public void createAcceptActionUsagePayload(EClass eClass) {
}

@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
@Test
public void createAcceptActionUsageReceiver() {
@MethodSource("acceptActionUsageReceiverParameters")
@ParameterizedTest
public void createAcceptActionUsageReceiver(String selectedObjectId) {
var flux = this.givenSubscriptionToDiagram();

AtomicReference<String> 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);
Expand All @@ -299,8 +317,8 @@ public void createAcceptActionUsageReceiver() {
AtomicReference<Diagram> diagram = new AtomicReference<>();
Consumer<Object> 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<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
new CheckDiagramElementCount(this.diagramComparator)
Expand All @@ -314,7 +332,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) -> {
Expand All @@ -332,13 +350,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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.emf.ecore.EClass;
Expand Down Expand Up @@ -56,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;
Expand Down Expand Up @@ -634,23 +636,20 @@ public Element createAcceptActionPayload(AcceptActionUsage self, String payloadE
* 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);
Expand All @@ -671,6 +670,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) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add meaningful javadoc

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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()
Expand All @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ image::release-notes-port-inherited-item-border-nodes.png[ItemUsage border node

** Improve the edge tool creating a `FlowUsage`, by creating a `ReferenceUsage` used for the redefinition of the `FlowEnd` only when it is needed.
** Fix the edge tool creating a `ConnectionUsage` between an `ActionUsage` graphical node and the _done_ `ActionUsage` graphical node.
** Add the capability of selecting an existing `PortUsage` in `New Port as Receiver` tool on `AcceptAction` graphical node.
The creation of a new port remains available.

== Bug fixes

Expand Down
Loading