diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8d29c4039..38f2a3af0 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -36,6 +36,7 @@ It has long been unused by Sirius Web itself (since the transition to MUI). - https://github.com/eclipse-syson/syson/issues/2306[#2306] [diagrams] Fixed an error when trying to rename a constraint displayed as a list item through direct edit. === Improvements + - https://github.com/eclipse-syson/syson/issues/2198[#2198] [diagrams] Improve diagram-to-diagram drag and drop to support dropping multiple graphical nodes at once, leveraging Sirius Web's `droppedNodes` and `droppedElements` variables. - https://github.com/eclipse-syson/syson/issues/2182[#2182] [services] Provide a way for downstream applications to extend _ISysMLMoveElementService_. - https://github.com/eclipse-syson/syson/issues/2240[#2240] [diagrams] Update the choice of _timeslice_ and _snapshot_ elements that can be created in the selection dialog of tools creating _timeslice_ and _snapshot_ elements. @@ -75,6 +76,7 @@ It leverages the selection dialog to either create an _occurrence timeslice/snap - https://github.com/eclipse-syson/syson/issues/2113[#2113] [diagrams] Handle start/end/merge/decision... graphical nodes on Action Flow View diagram background - https://github.com/eclipse-syson/syson/issues/2303[#2303] [diagrams] Add support for list item inheritance in _states_ and _exhibit states_ compartments - https://github.com/eclipse-syson/syson/issues/2239[#2239] [diagrams] Add the support for a frontend tool to rotate `ForkNode` and `JoinNode` graphical nodes +- https://github.com/eclipse-syson/syson/issues/2316[#2316] [diagrams] Add support for list item inheritance in _perform actions_ compartments == v2026.5.0 diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVCompartmentItemInheritanceTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVCompartmentItemInheritanceTests.java index 4161bfef1..0417ef20a 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVCompartmentItemInheritanceTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVCompartmentItemInheritanceTests.java @@ -344,6 +344,55 @@ public void checkStateUsageExhibitStatesInheritanceWithRedefinition() { .run(); } + @DisplayName("GIVEN a base ActionDefinition with a perform action, WHEN another ActionDefinition is subclassing the base ActionDefinition, THEN the base ActionDefinition perform actions are inherited by the other ActionDefinition") + @Test + public void checkActionDefinitionPerformActionsInheritanceWithSubclassification() { + new ElementSpecializationInheritanceTestRunner() + .baseElementToInheritFromEClass(SysmlPackage.eINSTANCE.getActionDefinition()) + .baseElementToInheritFromNodeId(GeneralViewWithTopNodesTestProjectData.GraphicalIds.ACTION_DEFINITION_ID) + .elementToInheritCreationToolName("New Perform action") + .withEdgeExpected() + .withSelectedElementId("") + .elementToInheritExpectedListItemLabelText("ref ") + .compartmentName("perform actions") + .elementThatInheritFromBaseElementCreationToolName("New Action Definition") + .elementThatInheritFromBaseElementEClass(SysmlPackage.eINSTANCE.getActionDefinition()) + .specializationToolName("New Subclassification") + .run(); + } + + @DisplayName("GIVEN a StateDefinition with a do action, WHEN a StateUsage is typed by the StateDefinition, THEN the StateDefinition perform actions are inherited by the StateUsage") + @Test + public void checkStateDefinitionPerformActionsInheritanceWithFeatureTyping() { + new ElementSpecializationInheritanceTestRunner() + .baseElementToInheritFromEClass(SysmlPackage.eINSTANCE.getStateDefinition()) + .baseElementToInheritFromNodeId(GeneralViewWithTopNodesTestProjectData.GraphicalIds.STATE_DEFINITION_ID) + .elementToInheritCreationToolName("New Do Action") + .withSelectedElementId(GeneralViewWithTopNodesTestProjectData.SemanticIds.ACTION_USAGE_ID) + .elementToInheritExpectedListItemLabelText("ref do ::> action") + .compartmentName("perform actions") + .elementThatInheritFromBaseElementCreationToolName("New State") + .elementThatInheritFromBaseElementEClass(SysmlPackage.eINSTANCE.getStateUsage()) + .specializationToolName("New Feature Typing") + .run(); + } + + @DisplayName("GIVEN a StateUsage with an entry action, WHEN a PartUsage is subsetting by reference the StateUsage, THEN the StateUsage perform actions are inherited by the PartUsage") + @Test + public void checkStateUsagePerformActionsInheritanceWithReferenceSubsetting() { + new ElementSpecializationInheritanceTestRunner() + .baseElementToInheritFromEClass(SysmlPackage.eINSTANCE.getStateUsage()) + .baseElementToInheritFromNodeId(GeneralViewWithTopNodesTestProjectData.GraphicalIds.STATE_USAGE_ID) + .elementToInheritCreationToolName("New Entry Action") + .withSelectedElementId(GeneralViewWithTopNodesTestProjectData.SemanticIds.ACTION_USAGE_ID) + .elementToInheritExpectedListItemLabelText("ref entry ::> action") + .compartmentName("perform actions") + .elementThatInheritFromBaseElementCreationToolName("New Part") + .elementThatInheritFromBaseElementEClass(SysmlPackage.eINSTANCE.getPartUsage()) + .specializationToolName("New Reference Subsetting") + .run(); + } + /** * This test runner verifies that creating a specializing relationship create inherited elements. * diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/InheritedCompartmentItemFilterSwitch.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/InheritedCompartmentItemFilterSwitch.java index e0cfd3a00..89a828ff6 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/InheritedCompartmentItemFilterSwitch.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/InheritedCompartmentItemFilterSwitch.java @@ -19,6 +19,7 @@ import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; +import org.eclipse.syson.sysml.ActionUsage; import org.eclipse.syson.sysml.Behavior; import org.eclipse.syson.sysml.ConstraintUsage; import org.eclipse.syson.sysml.Definition; @@ -26,6 +27,7 @@ import org.eclipse.syson.sysml.Feature; import org.eclipse.syson.sysml.OwningMembership; import org.eclipse.syson.sysml.PartUsage; +import org.eclipse.syson.sysml.PerformActionUsage; import org.eclipse.syson.sysml.ReferenceUsage; import org.eclipse.syson.sysml.RequirementConstraintKind; import org.eclipse.syson.sysml.RequirementConstraintMembership; @@ -79,13 +81,11 @@ public Boolean caseExhibitStateUsage(ExhibitStateUsage object) { // Add this behavior parameter check for each caseXXXUsage. // In this case, we want to display inherited parameters (directed feature) but not all features with the same // type. - if (!shouldKeep && this.shouldConsiderParameter(object)) { + if (this.shouldConsiderParameter(object)) { shouldKeep = this.isInheritedParameter(object); - } - if (!shouldKeep && this.shouldConsiderExhibitState(object)) { + } else if (this.shouldConsiderExhibitState(object)) { shouldKeep = this.isInheritedState(object); - } - if (!shouldKeep) { + } else { shouldKeep = super.caseExhibitStateUsage(object); } return shouldKeep; @@ -115,6 +115,22 @@ public Boolean casePartUsage(PartUsage object) { return eType.equals(eClass) || (eType instanceof EClass eTypeEClass && eTypeEClass.isSuperTypeOf(eClass)); } + @Override + public Boolean casePerformActionUsage(PerformActionUsage object) { + Boolean shouldKeep = Boolean.FALSE; + // Add this behavior parameter check for each caseXXXUsage. + // In this case, we want to display inherited parameters (directed feature) but not all features with the same + // type. + if (this.shouldConsiderParameter(object)) { + shouldKeep = this.isInheritedParameter(object); + } else if (this.shouldConsiderPerformUsage(object)) { + shouldKeep = this.isInheritedAction(object); + } else { + shouldKeep = super.casePerformActionUsage(object); + } + return shouldKeep; + } + @Override public Boolean caseReferenceUsage(ReferenceUsage object) { // Add this behavior parameter check for each caseXXXUsage. @@ -162,4 +178,23 @@ private boolean isInheritedState(Feature feature) { }; return featureState.contains(feature); } + + private boolean shouldConsiderPerformUsage(Feature feature) { + if (!(feature instanceof PerformActionUsage)) { + return false; + } + + EClassifier eType = this.eReference.getEType(); + EClass eClass = feature.eClass(); + return eType.equals(eClass) || (eType instanceof EClass eTypeEClass && eTypeEClass.isSuperTypeOf(eClass)); + } + + private boolean isInheritedAction(Feature feature) { + List< ActionUsage> featureActions = switch (feature.getOwner()) { + case Definition definition -> definition.getOwnedAction(); + case Usage usage -> usage.getNestedAction(); + default -> List.of(); + }; + return featureActions.contains(feature); + } } 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 a21b166b9..f6600f759 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 @@ -131,6 +131,7 @@ import org.eclipse.syson.standard.diagrams.view.nodes.ObjectiveDocumentationCompartmentItemNodeDescription; import org.eclipse.syson.standard.diagrams.view.nodes.PerformActionsCompartmentItemNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.PerformActionsCompartmentNodeDescriptionProvider; +import org.eclipse.syson.standard.diagrams.view.nodes.PerformActionsInheritedCompartmentItemNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.PortDefinitionOwnedItemBorderNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.PortDefinitionOwnedItemCompartmentItemNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.PortUsageBorderNodeDescriptionProvider; @@ -639,6 +640,7 @@ private List> createCompartmentsForListIte compartmentNodeDescriptionProviders.add(new CompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); compartmentNodeDescriptionProviders.add(new InheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); + compartmentNodeDescriptionProviders.add(new PerformActionsInheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new PerformActionsCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new PerformActionsCompartmentNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); } else if ((SysmlPackage.eINSTANCE.getPartUsage().equals(eClass) && SysmlPackage.eINSTANCE.getUsage_NestedAction().equals(eReference)) @@ -646,6 +648,7 @@ private List> createCompartmentsForListIte compartmentNodeDescriptionProviders.add(new ActionItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); compartmentNodeDescriptionProviders.add(new InheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); + compartmentNodeDescriptionProviders.add(new PerformActionsInheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new PerformActionsCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new PerformActionsCompartmentNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); } else if ((SysmlPackage.eINSTANCE.getPartUsage().equals(eClass) && SysmlPackage.eINSTANCE.getUsage_NestedState().equals(eReference)) @@ -661,6 +664,7 @@ private List> createCompartmentsForListIte compartmentNodeDescriptionProviders.add(new CompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); compartmentNodeDescriptionProviders.add(new InheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); + compartmentNodeDescriptionProviders.add(new PerformActionsInheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new PerformActionsCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); compartmentNodeDescriptionProviders.add(new PerformActionsCompartmentNodeDescriptionProvider(eClass, eReference, colorProvider, this.getDescriptionNameGenerator())); } else if (SysmlPackage.eINSTANCE.getPortDefinition().equals(eClass) && SysmlPackage.eINSTANCE.getDefinition_OwnedItem().equals(eReference)) { diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsCompartmentNodeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsCompartmentNodeDescriptionProvider.java index 6c1f22ed5..0561de936 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsCompartmentNodeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsCompartmentNodeDescriptionProvider.java @@ -64,6 +64,7 @@ protected List getDroppableNodes(IViewDiagramElementFinder cach public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { cache.getNodeDescription(this.getDescriptionNameGenerator().getCompartmentName(this.eClass, this.eReference) + PERFORM_ACTIONS_COMPARTMENT_NAME).ifPresent(nd -> { cache.getNodeDescription(this.getDescriptionNameGenerator().getCompartmentItemName(this.eClass, this.eReference) + PERFORM_ACTIONS_COMPARTMENT_NAME).ifPresent(nd.getChildrenDescriptions()::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getInheritedCompartmentItemName(this.eClass, this.eReference) + PERFORM_ACTIONS_COMPARTMENT_NAME).ifPresent(nd.getChildrenDescriptions()::add); nd.setPalette(this.createCompartmentPalette(cache)); }); } diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsInheritedCompartmentItemNodeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsInheritedCompartmentItemNodeDescriptionProvider.java new file mode 100644 index 000000000..b3df61f25 --- /dev/null +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/PerformActionsInheritedCompartmentItemNodeDescriptionProvider.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * 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.standard.diagrams.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.diagram.common.view.nodes.InheritedCompartmentItemNodeDescriptionProvider; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.SysMLMetamodelHelper; + +/** + * The inherited perform action compartment list item node description provider. + * + * @author gcoutable + */ +public class PerformActionsInheritedCompartmentItemNodeDescriptionProvider extends InheritedCompartmentItemNodeDescriptionProvider { + public PerformActionsInheritedCompartmentItemNodeDescriptionProvider(EClass eClass, EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(eClass, eReference, colorProvider, descriptionNameGenerator); + } + + @Override + public NodeDescription create() { + NodeDescription nd = super.create(); + var qualifiedName = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getPerformActionUsage()); + nd.setName(this.descriptionNameGenerator.getInheritedCompartmentItemName(this.eClass, this.eReference) + PerformActionsCompartmentNodeDescriptionProvider.PERFORM_ACTIONS_COMPARTMENT_NAME); + nd.setDomainType(qualifiedName); + nd.setPreconditionExpression(AQLConstants.AQL_SELF + ".oclIsTypeOf(" + qualifiedName + ")"); + return nd; + } +} 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 50b73cff4..2ae2dfc80 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 @@ -55,6 +55,8 @@ Users should use the dedicated tools to edit expressions instead, as they ensure + image::release-notes-rotate-fork-join-graphical-nodes.png[For both fork nodes and two join nodes, display one horizontal and one vertical graphical node. Also display the palette with the rotate tool, width=50%,height=50%] +** Add support for list item inheritance in _perform actions_ compartments. + * In the _Explorer_ view: ** The tree items corresponding to the internals of `Expression` elements (syntax tree) are now hidden by default.