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 @@ -114,6 +114,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/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.

== v20
== v2026.7.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ public class GVSubNodeActionFlowCreationTests extends AbstractIntegrationTests {

private static Stream<Arguments> acceptActionUsagePayloadParameters() {
return Stream.of(
Arguments.of(SysmlPackage.eINSTANCE.getPartDefinition()),
Arguments.of(SysmlPackage.eINSTANCE.getItemDefinition()))
.map(TestNameGenerator::namedArguments);
Arguments.of(SysmlPackage.eINSTANCE.getPartDefinition(), ""),
Arguments.of(SysmlPackage.eINSTANCE.getPartDefinition(), GeneralViewWithTopNodesTestProjectData.SemanticIds.PART_DEFINITION_ID),
Arguments.of(SysmlPackage.eINSTANCE.getItemDefinition(), ""),
Arguments.of(SysmlPackage.eINSTANCE.getItemDefinition(), GeneralViewWithTopNodesTestProjectData.SemanticIds.ITEM_DEFINITION_ID)
);
}

private static Stream<Arguments> actionUsageSiblingNodeParameters() {
Expand Down Expand Up @@ -223,9 +225,19 @@ public void setUp() {
@GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH })
@ParameterizedTest
@MethodSource("acceptActionUsagePayloadParameters")
public void createAcceptActionUsagePayload(EClass eClass) {
public void createAcceptActionUsagePayload(EClass eClass, String selectedNodeId) {
var flux = this.givenSubscriptionToDiagram();

AtomicReference<String> expectedPayloadTypeName = new AtomicReference<>();
ISemanticChecker initialSemanticChecker = (editingContext) -> {
expectedPayloadTypeName.set(this.objectSearchService.getObject(editingContext, selectedNodeId)
.filter(Element.class::isInstance)
.map(Element.class::cast)
.map(Element::getDeclaredName)
.orElse("acceptActionPayloadType"));
};
Runnable initialSemanticCheck = this.semanticCheckerService.checkEditingContext(initialSemanticChecker);

AtomicReference<Diagram> diagram = new AtomicReference<>();
Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set);

Expand All @@ -236,8 +248,8 @@ public void createAcceptActionUsagePayload(EClass eClass) {
EClass parentEClass = SysmlPackage.eINSTANCE.getAcceptActionUsage();
String targetObjectId = GeneralViewWithTopNodesTestProjectData.SemanticIds.ACCEPT_ACTION_USAGE_ID;

Runnable createNodeRunnable = this.creationTestsService.createNode(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId,
this.descriptionNameGenerator.getCreationToolName("New {0} as Payload", eClass));
Runnable createNodeRunnable = this.creationTestsService.createNodeWithSelectionDialogWithSingleSelection(diagramDescriptionIdProvider, diagram, parentEClass, targetObjectId,
this.descriptionNameGenerator.getCreationToolName("New {0} as Payload", eClass), selectedNodeId);

Consumer<Object> diagramCheck = assertRefreshedDiagramThat(newDiagram -> {
new CheckDiagramElementCount(this.diagramComparator)
Expand All @@ -251,7 +263,7 @@ public void createAcceptActionUsagePayload(EClass eClass) {
assertThat(updatedNode.getInsideLabel()).as("The updated node label should exist").isNotNull();
assertThat(updatedNode.getInsideLabel().getText())
.contains(LabelConstants.OPEN_QUOTE + "accept" + LabelConstants.CLOSE_QUOTE)
.contains("payload: acceptActionPayloadType");
.contains("payload: " + expectedPayloadTypeName.get());
});

ISemanticChecker semanticChecker = (editingContext) -> {
Expand All @@ -269,13 +281,14 @@ public void createAcceptActionUsagePayload(EClass eClass) {
assertThat(relationship).isInstanceOf(FeatureTyping.class);
FeatureTyping featureTyping = (FeatureTyping) relationship;
assertThat(eClass.isInstance(featureTyping.getType()));
assertThat(featureTyping.getType().getName()).isEqualTo("acceptActionPayloadType");
assertThat(featureTyping.getType().getName()).isEqualTo(expectedPayloadTypeName.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 @@ -596,38 +597,51 @@ public Element createAcceptAction(Element ownerElement) {
* Create or replace the payload parameter of an accept action usage.
*
* @param self
* the accept action usage
* the accept action usage
* @param payloadEClassName
* the payload classifier name
* the payload classifier name
* @param selectedObject
* the payload classifier given by the selection dialog
* @return the given accept action usage
*/
public Element createAcceptActionPayload(AcceptActionUsage self, String payloadEClassName) {
public Element createAcceptActionPayload(AcceptActionUsage self, String payloadEClassName, Element selectedObject) {
var payloadType = Optional.ofNullable(selectedObject)
.filter(Type.class::isInstance)
.map(Type.class::cast)
.orElse(this.createNewAcceptActionPayload(payloadEClassName, self));
if (payloadType != null) {
var featureTyping = SysmlFactory.eINSTANCE.createFeatureTyping();
featureTyping.setType(payloadType);
var referenceUsage = SysmlFactory.eINSTANCE.createReferenceUsage();
referenceUsage.setDeclaredName("payload");
referenceUsage.setDirection(FeatureDirectionKind.INOUT);
referenceUsage.getOwnedRelationship().add(featureTyping);
var parameterMembership = this.getPayloadParameterMembership(self);
var oldParameterContent = parameterMembership.getOwnedMemberParameter();
if (oldParameterContent != null) {
this.deleteService.deleteFromModel(oldParameterContent);
}
parameterMembership = this.getPayloadParameterMembership(self);
parameterMembership.getOwnedRelatedElement().add(referenceUsage);
self.getOwnedRelationship().add(parameterMembership);
}
return self;
}

private Type createNewAcceptActionPayload(String payloadEClassName, AcceptActionUsage acceptActionName) {
var classifier = SysmlPackage.eINSTANCE.getEClassifier(payloadEClassName);
if (classifier instanceof EClass eClass) {
var payload = SysmlFactory.eINSTANCE.create(eClass);
if (payload instanceof Type payloadType) {
payloadType.setDeclaredName(self.getDeclaredName() + "PayloadType");
payloadType.setDeclaredName(acceptActionName.getDeclaredName() + "PayloadType");
var membership = SysmlFactory.eINSTANCE.createOwningMembership();
membership.getOwnedRelatedElement().add(payloadType);
var payloadParent = this.getClosestContainingPackageFrom(self);
var payloadParent = this.getClosestContainingPackageFrom(acceptActionName);
payloadParent.getOwnedRelationship().add(membership);
var featureTyping = SysmlFactory.eINSTANCE.createFeatureTyping();
featureTyping.setType(payloadType);
var referenceUsage = SysmlFactory.eINSTANCE.createReferenceUsage();
referenceUsage.setDeclaredName("payload");
referenceUsage.setDirection(FeatureDirectionKind.INOUT);
referenceUsage.getOwnedRelationship().add(featureTyping);
var parameterMembership = this.getPayloadParameterMembership(self);
var oldParameterContent = parameterMembership.getOwnedMemberParameter();
if (oldParameterContent != null) {
this.deleteService.deleteFromModel(oldParameterContent);
}
parameterMembership = this.getPayloadParameterMembership(self);
parameterMembership.getOwnedRelatedElement().add(referenceUsage);
self.getOwnedRelationship().add(parameterMembership);
return payloadType;
}
}
return self;
return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ public Element createAcceptAction(Element ownerElement) {
}

/**
* {@link DiagramMutationToolService#createAcceptActionPayload(AcceptActionUsage, String)}.
* {@link DiagramMutationToolService#createAcceptActionPayload(AcceptActionUsage, String, Element)}.
*/
public Element createAcceptActionPayload(AcceptActionUsage self, String payloadEClassName) {
return this.diagramMutationToolService.createAcceptActionPayload(self, payloadEClassName);
public Element createAcceptActionPayload(AcceptActionUsage self, String payloadEClassName, Element selectedObject) {
return this.diagramMutationToolService.createAcceptActionPayload(self, payloadEClassName, selectedObject);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* 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
Expand All @@ -12,16 +12,25 @@
*******************************************************************************/
package org.eclipse.syson.diagram.common.view.tools;

import java.util.List;
import java.util.Objects;

import org.eclipse.emf.ecore.EClass;
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.tree.services.aql.TreeQueryAQLService;
import org.eclipse.syson.util.AQLConstants;
import org.eclipse.syson.util.AQLUtils;
import org.eclipse.syson.util.IDescriptionNameGenerator;
import org.eclipse.syson.util.ServiceMethod;
import org.eclipse.syson.util.SysMLMetamodelHelper;

/**
* Used to create element as a payload of an accept action usage.
Expand All @@ -48,7 +57,7 @@ public NodeTool create(IViewDiagramElementFinder cache) {
var builder = this.diagramBuilderHelper.newNodeTool();

var creationPayloadServiceCall = this.viewBuilderHelper.newChangeContext()
.expression(AQLConstants.AQL_SELF + ".createAcceptActionPayload('" + this.payloadEClass.getName() + "')")
.expression(ServiceMethod.of2(DiagramMutationAQLService::createAcceptActionPayload).aqlSelf(AQLUtils.aqlString(this.payloadEClass.getName()), "selectedObject"))
.build();

var rootChangContext = this.viewBuilderHelper.newChangeContext()
Expand All @@ -60,6 +69,31 @@ public NodeTool create(IViewDiagramElementFinder cache) {
.iconURLsExpression("/icons/full/obj16/" + this.payloadEClass.getName() + ".svg")
.body(rootChangContext)
.preconditionExpression(AQLConstants.AQL_SELF + ".isEmptyAcceptActionUsagePayload()")
.dialogDescription(this.getSelectionDialogDescription())
.build();
}

private DialogDescription getSelectionDialogDescription() {
var payloadTypeName = SysMLMetamodelHelper.buildQualifiedName(this.payloadEClass);
var selectionDialogTree = this.diagramBuilderHelper.newSelectionDialogTreeDescription()
.elementsExpression(ServiceMethod.of1(TreeQueryAQLService::getSelectionDialogElements).aql(IEditingContext.EDITING_CONTEXT, AQLUtils.aqlSequence(List.of(payloadTypeName))))
.childrenExpression(
ServiceMethod.of3(TreeQueryAQLService::getSelectionDialogChildren).aqlSelf(IEditingContext.EDITING_CONTEXT, TreeRenderer.EXPANDED, AQLUtils.aqlSequence(List.of(payloadTypeName))))
.isSelectableExpression(AQLConstants.AQL_SELF + ".oclIsKindOf(" + payloadTypeName + ")")
.build();
String payloadName = this.payloadEClass.getName();
return this.diagramBuilderHelper.newSelectionDialogDescription()
.selectionDialogTreeDescription(selectionDialogTree)
.defaultTitleExpression("Set payload")
.descriptionExpression(payloadName + " as payload")
.noSelectionActionLabelExpression("Create a New " + payloadName)
.noSelectionActionDescriptionExpression("Set the payload with a New " + payloadName)
.withSelectionActionLabelExpression("Select an existing " + payloadName)
.withSelectionActionDescriptionExpression("Set the payload with an existing " + payloadName)
.noSelectionActionStatusMessageExpression("It will set the payload with a New " + payloadName)
.selectionRequiredWithoutSelectionStatusMessageExpression("Select one " + payloadName)
.selectionRequiredWithSelectionStatusMessageExpression(AQLConstants.AQL + "'It will set the payload with ' + selectedObjects->first().name")
.optional(true)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ 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 element in `New ItemDefinition as Payload` and `New PartDefinition as Payload` tools on `AcceptAction` graphical node. The creation a new element remains available.

== Bug fixes

Expand Down
Loading