From 922579b5879d0b4654deeefe348c06c422a8fc0b Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Fri, 19 Dec 2025 14:56:59 +0100 Subject: [PATCH] [1778] Add ReferenceSubsetting tool Bug: https://github.com/eclipse-syson/syson/issues/1778 Signed-off-by: Axel RICHARD --- CHANGELOG.adoc | 1 + .../SysMLv2PropertiesConfigurer.java | 28 ++++ .../services/DetailsViewService.java | 2 + .../services/GetChildCreationSwitch.java | 1 + .../services/DiagramQueryLabelService.java | 25 ++- .../services/api/IDiagramLabelService.java | 10 ++ .../services/utils/MultiLineLabelSwitch.java | 18 ++ .../services/DiagramDirectEditListener.java | 3 +- .../syson/services/RelatedElementsSwitch.java | 3 + .../eclipse/syson/services/UtilService.java | 2 +- ...ractSubsettingEdgeDescriptionProvider.java | 127 +++++--------- .../view/services/ViewEdgeToolService.java | 76 ++++++++- .../view/services/ViewEdgeToolSwitch.java | 1 + .../view/SDVDiagramDescriptionProvider.java | 6 +- ...enceSubsettingEdgeDescriptionProvider.java | 157 ++++++++++++++++++ .../SubsettingEdgeDescriptionProvider.java | 112 +++++++++++-- .../pages/release-notes/2026.1.0.adoc | 2 +- 17 files changed, 466 insertions(+), 108 deletions(-) create mode 100644 backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/ReferenceSubsettingEdgeDescriptionProvider.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 3bd2a8a9f..55f17209d 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -42,6 +42,7 @@ This fix ensure that imported models containing, for example, a top-level `Libra - https://github.com/eclipse-syson/syson/issues/1765[#1765] [diagrams] Allow to create a `SatisfyRequirement` on `PartDefinition` or `PartUsage`. A new compartment named _satisfy requirements_ has also been added to `PartDefinition` and `PartUsage` graphical nodes in diagrams. - https://github.com/eclipse-syson/syson/issues/1762[#1762] [diagrams] Increase the default size of nodes. +- https://github.com/eclipse-syson/syson/issues/1778[#1778] [diagrams] Add new `ReferenceSubsetting` tool to create `ReferenceSubsetting` relationships between `Usage` elements in diagrams. === New features diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/configuration/SysMLv2PropertiesConfigurer.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/configuration/SysMLv2PropertiesConfigurer.java index c6e778df0..ff706d195 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/configuration/SysMLv2PropertiesConfigurer.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/configuration/SysMLv2PropertiesConfigurer.java @@ -80,6 +80,8 @@ public class SysMLv2PropertiesConfigurer implements IPropertiesDescriptionRegist private static final String ADVANCED_PROPERTIES = "Advanced Properties"; + private static final String REFERENCE_SUBSETTING_PROPERTIES = "Reference Subsetting Properties"; + private static final String REDEFINITION_PROPERTIES = "Redefinition Properties"; private static final String SUBCLASSIFICATION_PROPERTIES = "Subclassification Properties"; @@ -170,6 +172,7 @@ private FormDescription createDetailsViewForElement() { pageCore.setLabelExpression("Core"); pageCore.getGroups().add(this.createCorePropertiesGroup()); pageCore.getGroups().add(this.createVisibilityPropertyGroup()); + pageCore.getGroups().add(this.createExtraReferenceSubsettingPropertiesGroup()); pageCore.getGroups().add(this.createExtraRedefinitionPropertiesGroup()); pageCore.getGroups().add(this.createExtraStatesubactionMembershipKindPropertiesGroup()); pageCore.getGroups().add(this.createExtraSubclassificationPropertiesGroup()); @@ -267,6 +270,31 @@ private GroupDescription createExtraRedefinitionPropertiesGroup() { return group; } + // should handle multiple ReferenceSubsetting + private GroupDescription createExtraReferenceSubsettingPropertiesGroup() { + GroupDescription group = FormFactory.eINSTANCE.createGroupDescription(); + group.setDisplayMode(GroupDisplayMode.LIST); + group.setName(REFERENCE_SUBSETTING_PROPERTIES); + group.setLabelExpression(""); + group.setSemanticCandidatesExpression("aql:self.ownedRelationship->filter(sysml::ReferenceSubsetting)"); + + ReferenceWidgetDescription refWidget = ReferenceFactory.eINSTANCE.createReferenceWidgetDescription(); + refWidget.setName("ExtraReferenceWidget"); + refWidget.setLabelExpression("References"); + refWidget.setReferenceNameExpression(SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName()); + refWidget.setReferenceOwnerExpression(AQLConstants.AQL_SELF); + refWidget.setIsEnabledExpression(AQL_NOT_SELF_IS_READ_ONLY); + ChangeContext setRefWidget = ViewFactory.eINSTANCE.createChangeContext(); + setRefWidget + .setExpression("aql:self.handleReferenceWidgetNewValue('" + SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName() + "', " + ViewFormDescriptionConverter.NEW_VALUE + + LabelConstants.CLOSE_PARENTHESIS); + refWidget.getBody().add(setRefWidget); + + group.getChildren().add(refWidget); + + return group; + } + private GroupDescription createExtraStatesubactionMembershipKindPropertiesGroup() { GroupDescription group = FormFactory.eINSTANCE.createGroupDescription(); group.setDisplayMode(GroupDisplayMode.LIST); diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/DetailsViewService.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/DetailsViewService.java index 523f67c4e..a2cb866c2 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/DetailsViewService.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/DetailsViewService.java @@ -659,6 +659,8 @@ private void handleImplied(Element element, EStructuralFeature eStructuralFeatur if (element instanceof Relationship relationship) { if (SysmlPackage.eINSTANCE.getRedefinition_RedefinedFeature().equals(eStructuralFeature)) { relationship.setIsImplied(false); + } else if (SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().equals(eStructuralFeature)) { + relationship.setIsImplied(false); } else if (SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().equals(eStructuralFeature)) { relationship.setIsImplied(false); } else if (SysmlPackage.eINSTANCE.getSubclassification_Superclassifier().equals(eStructuralFeature)) { diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/GetChildCreationSwitch.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/GetChildCreationSwitch.java index e69612984..d8eb79ce5 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/GetChildCreationSwitch.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/GetChildCreationSwitch.java @@ -242,6 +242,7 @@ public List caseUsage(Usage object) { childrenCandidates.add(SysmlPackage.eINSTANCE.getFeatureTyping()); childrenCandidates.add(SysmlPackage.eINSTANCE.getSubsetting()); childrenCandidates.add(SysmlPackage.eINSTANCE.getRedefinition()); + childrenCandidates.add(SysmlPackage.eINSTANCE.getReferenceSubsetting()); childrenCandidates.add(SysmlPackage.eINSTANCE.getLiteralBoolean()); childrenCandidates.add(SysmlPackage.eINSTANCE.getLiteralInfinity()); childrenCandidates.add(SysmlPackage.eINSTANCE.getLiteralInteger()); diff --git a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java index 37ab0ef47..016f0a814 100644 --- a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java +++ b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java @@ -40,6 +40,7 @@ import org.eclipse.syson.sysml.MultiplicityRange; import org.eclipse.syson.sysml.OwningMembership; import org.eclipse.syson.sysml.Redefinition; +import org.eclipse.syson.sysml.ReferenceSubsetting; import org.eclipse.syson.sysml.RequirementConstraintMembership; import org.eclipse.syson.sysml.StateSubactionMembership; import org.eclipse.syson.sysml.Subclassification; @@ -98,6 +99,28 @@ public String getIdentificationLabel(Element element) { return label.toString(); } + @Override + public String getReferenceSubsettingLabel(Element element) { + StringBuilder label = new StringBuilder(); + var optReferenceSubsetting = element.getOwnedRelationship().stream() + .filter(ReferenceSubsetting.class::isInstance) + .map(ReferenceSubsetting.class::cast) + .findFirst(); + if (optReferenceSubsetting.isPresent()) { + ReferenceSubsetting referenceSubsetting = optReferenceSubsetting.get(); + if (!referenceSubsetting.isIsImplied()) { + var referencedFeature = referenceSubsetting.getReferencedFeature(); + if (referencedFeature != null) { + label.append(LabelConstants.SPACE); + label.append(LabelConstants.REFERENCES); + label.append(LabelConstants.SPACE); + label.append(this.getDeclaredNameLabel(referencedFeature)); + } + } + } + return label.toString(); + } + @Override public String getRedefinitionLabel(Element element) { StringBuilder label = new StringBuilder(); @@ -146,7 +169,7 @@ public String getSubclassificationLabel(Element element) { public String getSubsettingLabel(Element element) { StringBuilder label = new StringBuilder(); var optSubsetting = element.getOwnedRelationship().stream() - .filter(r -> r instanceof Subsetting && !(r instanceof Redefinition)) + .filter(r -> r instanceof Subsetting && !(r instanceof Redefinition) && !(r instanceof ReferenceSubsetting)) .map(Subsetting.class::cast) .findFirst(); if (optSubsetting.isPresent()) { diff --git a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/api/IDiagramLabelService.java b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/api/IDiagramLabelService.java index 3abc37330..1a85a636b 100644 --- a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/api/IDiagramLabelService.java +++ b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/api/IDiagramLabelService.java @@ -62,6 +62,16 @@ public interface IDiagramLabelService { */ String getSubsettingLabel(Element element); + /** + * Return the label of the reference subsetting of the given {@link Element}. + * + * @param usage + * the given {@link Element}. + * @return the label of the reference subsetting of the given {@link Element} if there is one, an empty string + * otherwise. + */ + String getReferenceSubsettingLabel(Element element); + /** * Get the SysML textual representation of the given element. * diff --git a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/utils/MultiLineLabelSwitch.java b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/utils/MultiLineLabelSwitch.java index 8a7ed5c65..1e2925fcf 100644 --- a/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/utils/MultiLineLabelSwitch.java +++ b/backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/utils/MultiLineLabelSwitch.java @@ -111,6 +111,7 @@ public String caseAcceptActionUsage(AcceptActionUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)) .append(LabelConstants.CR) @@ -147,6 +148,7 @@ public String caseActionUsage(ActionUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -180,6 +182,7 @@ public String caseAllocationUsage(AllocationUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -212,6 +215,7 @@ public String caseAttributeUsage(AttributeUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -259,6 +263,7 @@ public String caseCaseUsage(CaseUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -315,6 +320,7 @@ public String caseConcernUsage(ConcernUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -348,6 +354,7 @@ public String caseConstraintUsage(ConstraintUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -437,6 +444,7 @@ public String caseExhibitStateUsage(ExhibitStateUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -470,6 +478,7 @@ public String caseInterfaceUsage(InterfaceUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -519,6 +528,7 @@ public String caseItemUsage(ItemUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -568,6 +578,7 @@ public String caseOccurrenceUsage(OccurrenceUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -612,6 +623,7 @@ public String casePartUsage(PartUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -663,6 +675,7 @@ public String casePortUsage(PortUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -687,6 +700,7 @@ public String caseReferenceUsage(ReferenceUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -720,6 +734,7 @@ public String caseRequirementUsage(RequirementUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -739,6 +754,7 @@ public String caseSatisfyRequirementUsage(SatisfyRequirementUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -772,6 +788,7 @@ public String caseUseCaseUsage(UseCaseUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); @@ -807,6 +824,7 @@ public String caseStateUsage(StateUsage object) { .append(this.multiplicityRange(object)) .append(this.labelService.getTypingLabel(object)) .append(this.labelService.getRedefinitionLabel(object)) + .append(this.labelService.getReferenceSubsettingLabel(object)) .append(this.labelService.getSubsettingLabel(object)) .append(this.labelService.getValueLabel(object)); return label.toString(); diff --git a/backend/services/syson-services/src/main/java/org/eclipse/syson/services/DiagramDirectEditListener.java b/backend/services/syson-services/src/main/java/org/eclipse/syson/services/DiagramDirectEditListener.java index e4142983e..d17f29fc0 100644 --- a/backend/services/syson-services/src/main/java/org/eclipse/syson/services/DiagramDirectEditListener.java +++ b/backend/services/syson-services/src/main/java/org/eclipse/syson/services/DiagramDirectEditListener.java @@ -94,6 +94,7 @@ import org.eclipse.syson.sysml.OwningMembership; import org.eclipse.syson.sysml.ParameterMembership; import org.eclipse.syson.sysml.Redefinition; +import org.eclipse.syson.sysml.ReferenceSubsetting; import org.eclipse.syson.sysml.ResultExpressionMembership; import org.eclipse.syson.sysml.Subclassification; import org.eclipse.syson.sysml.Subsetting; @@ -1151,7 +1152,7 @@ private void handleMissingSubsettingExpression(ParserRuleContext ctx) { if (this.element instanceof Usage && featureExpressions != null && this.isDeleteFeatureExpression(featureExpressions, featureExpressions.subsettingExpression(), LabelConstants.SUBSETTING)) { var subsetting = this.element.getOwnedRelationship().stream() - .filter(elt -> elt instanceof Subsetting && !(elt instanceof Redefinition)) + .filter(r -> r instanceof Subsetting && !(r instanceof Redefinition) && !(r instanceof ReferenceSubsetting)) .map(Subsetting.class::cast) .findFirst(); if (subsetting.isPresent()) { diff --git a/backend/services/syson-services/src/main/java/org/eclipse/syson/services/RelatedElementsSwitch.java b/backend/services/syson-services/src/main/java/org/eclipse/syson/services/RelatedElementsSwitch.java index c480702dc..cc75da8ec 100644 --- a/backend/services/syson-services/src/main/java/org/eclipse/syson/services/RelatedElementsSwitch.java +++ b/backend/services/syson-services/src/main/java/org/eclipse/syson/services/RelatedElementsSwitch.java @@ -120,6 +120,9 @@ public Set caseReferenceSubsetting(ReferenceSubsetting object) { } } } + if (this.eStructuralFeature.equals(SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature())) { + relatedElements.add(object); + } return relatedElements; } diff --git a/backend/services/syson-services/src/main/java/org/eclipse/syson/services/UtilService.java b/backend/services/syson-services/src/main/java/org/eclipse/syson/services/UtilService.java index ad14aec14..9eee5ac8e 100644 --- a/backend/services/syson-services/src/main/java/org/eclipse/syson/services/UtilService.java +++ b/backend/services/syson-services/src/main/java/org/eclipse/syson/services/UtilService.java @@ -750,7 +750,7 @@ public Usage setFeatureTyping(Usage usage, Type type) { */ public Usage setSubsetting(Usage subsettingUsage, Feature feature) { var optSubsetting = subsettingUsage.getOwnedRelationship().stream() - .filter(elt -> elt instanceof Subsetting && !(elt instanceof Redefinition)) + .filter(r -> r instanceof Subsetting && !(r instanceof Redefinition) && !(r instanceof ReferenceSubsetting)) .map(Subsetting.class::cast) .findFirst(); if (optSubsetting.isPresent()) { diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractSubsettingEdgeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractSubsettingEdgeDescriptionProvider.java index 000fe50c3..5e7d1cb8d 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractSubsettingEdgeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractSubsettingEdgeDescriptionProvider.java @@ -14,21 +14,17 @@ import java.util.List; +import org.eclipse.emf.ecore.EClass; import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; -import org.eclipse.sirius.components.view.builder.generated.view.ChangeContextBuilder; import org.eclipse.sirius.components.view.builder.providers.IColorProvider; -import org.eclipse.sirius.components.view.diagram.ArrowStyle; import org.eclipse.sirius.components.view.diagram.DiagramDescription; import org.eclipse.sirius.components.view.diagram.EdgeDescription; import org.eclipse.sirius.components.view.diagram.EdgeStyle; -import org.eclipse.sirius.components.view.diagram.LineStyle; import org.eclipse.sirius.components.view.diagram.NodeDescription; import org.eclipse.sirius.components.view.diagram.SynchronizationPolicy; import org.eclipse.syson.sysml.Subsetting; -import org.eclipse.syson.sysml.SysmlPackage; -import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.AQLUtils; import org.eclipse.syson.util.SysMLMetamodelHelper; -import org.eclipse.syson.util.ViewConstants; /** * Used to create the {@link Subsetting} edge description. @@ -37,8 +33,11 @@ */ public abstract class AbstractSubsettingEdgeDescriptionProvider extends AbstractEdgeDescriptionProvider { - public AbstractSubsettingEdgeDescriptionProvider(IColorProvider colorProvider) { + private final EClass eClass; + + public AbstractSubsettingEdgeDescriptionProvider(EClass eClass, IColorProvider colorProvider) { super(colorProvider); + this.eClass = eClass; } /** @@ -48,6 +47,24 @@ public AbstractSubsettingEdgeDescriptionProvider(IColorProvider colorProvider) { */ protected abstract String getName(); + /** + * Implementers should provide the source expression of this {@link EdgeDescription}. + * + * @param cache + * the cache used to retrieve node descriptions. + * @return the source expression of this {@link EdgeDescription}.s + */ + protected abstract String getSourceExpression(); + + /** + * Implementers should provide the target expression of this {@link EdgeDescription}. + * + * @param cache + * the cache used to retrieve node descriptions. + * @return the target expression of this {@link EdgeDescription}.s + */ + protected abstract String getTargetExpression(); + /** * Implementers should provide the list of {@link NodeDescription} that can be a source of this * {@link EdgeDescription}. @@ -68,98 +85,36 @@ public AbstractSubsettingEdgeDescriptionProvider(IColorProvider colorProvider) { */ protected abstract List getTargetNodes(IViewDiagramElementFinder cache); + /** + * Create the {@link EdgeStyle} for this {@link EdgeDescription}. + * + * @return a new {@link EdgeStyle}. + */ + protected abstract EdgeStyle createEdgeStyle(); + @Override public EdgeDescription create() { - String domainType = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getSubsetting()); + String domainType = SysMLMetamodelHelper.buildQualifiedName(this.eClass); return this.diagramBuilderHelper.newEdgeDescription() .domainType(domainType) .isDomainBasedEdge(true) .centerLabelExpression("") .name(this.getName()) - .semanticCandidatesExpression("aql:self.getAllReachable(" + domainType + ")") - .sourceExpression(AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) + .semanticCandidatesExpression(AQLUtils.getSelfServiceCallExpression("getAllReachable", domainType)) + .sourceExpression(this.getSourceExpression()) .style(this.createEdgeStyle()) .synchronizationPolicy(SynchronizationPolicy.SYNCHRONIZED) - .targetExpression(AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) + .targetExpression(this.getTargetExpression()) .build(); } @Override public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { - var optEdgeDescription = cache.getEdgeDescription(this.getName()); - EdgeDescription edgeDescription = optEdgeDescription.get(); - diagramDescription.getEdgeDescriptions().add(edgeDescription); - - edgeDescription.getSourceDescriptions().addAll(this.getSourceNodes(cache)); - edgeDescription.getTargetDescriptions().addAll(this.getTargetNodes(cache)); - - edgeDescription.setPalette(this.createEdgePalette(cache)); - } - - private EdgeStyle createEdgeStyle() { - return this.diagramBuilderHelper.newEdgeStyle() - .borderSize(0) - .color(this.colorProvider.getColor(ViewConstants.DEFAULT_EDGE_COLOR)) - .edgeWidth(1) - .lineStyle(LineStyle.SOLID) - .sourceArrowStyle(ArrowStyle.NONE) - .targetArrowStyle(ArrowStyle.INPUT_CLOSED_ARROW) - .build(); - } - - @Override - protected ChangeContextBuilder getSourceReconnectToolBody() { - var unsetOldSubsettingFeature = this.viewBuilderHelper.newUnsetValue() - .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) - .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); - - var setNewSubsettingFeature = this.viewBuilderHelper.newSetValue() - .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) - .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); - - var unsetOldSpecific = this.viewBuilderHelper.newUnsetValue() - .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) - .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); - - var setNewSpecific = this.viewBuilderHelper.newSetValue() - .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) - .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); - - var setNewContainer = this.viewBuilderHelper.newSetValue() - .featureName(SysmlPackage.eINSTANCE.getElement_OwnedRelationship().getName()) - .valueExpression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT); - - var changeContextNewContainer = this.viewBuilderHelper.newChangeContext() - .expression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET) - .children(setNewContainer.build()); - - return this.viewBuilderHelper.newChangeContext() - .expression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT) - .children(unsetOldSubsettingFeature.build(), unsetOldSpecific.build(), setNewSubsettingFeature.build(), - setNewSpecific.build(), changeContextNewContainer.build()); - } - - @Override - protected ChangeContextBuilder getTargetReconnectToolBody() { - var unsetOldSubsettedFeature = this.viewBuilderHelper.newUnsetValue() - .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) - .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); - - var setNewSubsettedFeature = this.viewBuilderHelper.newSetValue() - .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) - .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); - - var unsetOldGeneral = this.viewBuilderHelper.newUnsetValue() - .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) - .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); - - var setNewGeneral = this.viewBuilderHelper.newSetValue() - .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) - .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); - - return this.viewBuilderHelper.newChangeContext() - .expression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT) - .children(unsetOldSubsettedFeature.build(), unsetOldGeneral.build(), setNewSubsettedFeature.build(), - setNewGeneral.build()); + cache.getEdgeDescription(this.getName()).ifPresent(edgeDescription -> { + diagramDescription.getEdgeDescriptions().add(edgeDescription); + edgeDescription.getSourceDescriptions().addAll(this.getSourceNodes(cache)); + edgeDescription.getTargetDescriptions().addAll(this.getTargetNodes(cache)); + edgeDescription.setPalette(this.createEdgePalette(cache)); + }); } } diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolService.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolService.java index a7ce1e99e..d945d3412 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolService.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolService.java @@ -295,22 +295,22 @@ public EdgeTool createSubsettingEdgeTool(List targetElementDesc .variableName(NEW_INSTANCE) .children(changeContextNewInstance.build()); - String hasExistingSubsetting = "hasExistingSubsetting"; + String hasExistingReferenceSubsetting = "hasExistingSubsetting"; var feedback = this.viewBuilderHelper.newChangeContext() .expression(ServiceMethod.of1(DiagramQueryAQLService::infoMessage).aqlSelf(AQLUtils.aqlString("A subsetting already exists between these elements."))) .build(); var createIfPossible = this.viewBuilderHelper.newIf() - .conditionExpression(AQLConstants.AQL + "not " + hasExistingSubsetting) + .conditionExpression(AQLConstants.AQL + "not " + hasExistingReferenceSubsetting) .children(createInstance.build()); var informOtherwise = this.viewBuilderHelper.newIf() - .conditionExpression(AQLConstants.AQL + hasExistingSubsetting) + .conditionExpression(AQLConstants.AQL + hasExistingReferenceSubsetting) .children(feedback); var letExistingSubsetting = this.viewBuilderHelper.newLet() - .variableName(hasExistingSubsetting) + .variableName(hasExistingReferenceSubsetting) .valueExpression(AQLConstants.AQL_SELF + ".eContents(sysml::Subsetting).subsettedFeature->includes(" + EdgeDescription.SEMANTIC_EDGE_TARGET + ")") .children(createIfPossible.build(), informOtherwise.build()); @@ -326,6 +326,74 @@ public EdgeTool createSubsettingEdgeTool(List targetElementDesc .build(); } + public EdgeTool createReferenceSubsettingEdgeTool(List targetElementDescriptions) { + var builder = this.diagramBuilderHelper.newEdgeTool(); + + var callElementInitializerService = this.viewBuilderHelper.newChangeContext() + .expression(ServiceMethod.of0(ViewCreateService::elementInitializer).aqlSelf()); + + var setReferencedFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName()) + .valueExpression(AQLConstants.AQL + EdgeDescription.SEMANTIC_EDGE_TARGET); + + var setSubsettingFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) + .valueExpression(AQLConstants.AQL + EdgeDescription.SEMANTIC_EDGE_SOURCE); + + var setSubsettedFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) + .valueExpression(AQLConstants.AQL + EdgeDescription.SEMANTIC_EDGE_TARGET); + + var setSpecific = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) + .valueExpression(AQLConstants.AQL + EdgeDescription.SEMANTIC_EDGE_SOURCE); + + var setGeneral = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) + .valueExpression(AQLConstants.AQL + EdgeDescription.SEMANTIC_EDGE_TARGET); + + var changeContextNewInstance = this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + NEW_INSTANCE) + .children(callElementInitializerService.build(), setSubsettingFeature.build(), setReferencedFeature.build(), setSubsettedFeature.build(), + setSpecific.build(), setGeneral.build()); + + var createInstance = this.viewBuilderHelper.newCreateInstance() + .typeName(SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getReferenceSubsetting())) + .referenceName(SysmlPackage.eINSTANCE.getElement_OwnedRelationship().getName()) + .variableName(NEW_INSTANCE) + .children(changeContextNewInstance.build()); + + String hasExistingReferenceSubsetting = "hasExistingReferenceSubsetting"; + + var feedback = this.viewBuilderHelper.newChangeContext() + .expression(ServiceMethod.of1(DiagramQueryAQLService::infoMessage).aqlSelf(AQLUtils.aqlString("A reference subsetting already exists between these elements."))) + .build(); + + var createIfPossible = this.viewBuilderHelper.newIf() + .conditionExpression(AQLConstants.AQL + "not " + hasExistingReferenceSubsetting) + .children(createInstance.build()); + + var informOtherwise = this.viewBuilderHelper.newIf() + .conditionExpression(AQLConstants.AQL + hasExistingReferenceSubsetting) + .children(feedback); + + var letExistingSubsetting = this.viewBuilderHelper.newLet() + .variableName(hasExistingReferenceSubsetting) + .valueExpression(AQLConstants.AQL_SELF + ".eContents(sysml::ReferenceSubsetting).referencedFeature->includes(" + EdgeDescription.SEMANTIC_EDGE_TARGET + ")") + .children(createIfPossible.build(), informOtherwise.build()); + + var body = this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + EdgeDescription.SEMANTIC_EDGE_SOURCE) + .children(letExistingSubsetting.build()); + + return builder + .name(this.nameGenerator.getCreationToolName(SysmlPackage.eINSTANCE.getReferenceSubsetting())) + .iconURLsExpression(METAMODEL_ICONS_PATH + SysmlPackage.eINSTANCE.getReferenceSubsetting().getName() + SVG) + .body(body.build()) + .targetElementDescriptions(targetElementDescriptions.toArray(NodeDescription[]::new)) + .build(); + } + public EdgeTool createFeatureTypingEdgeTool(List targetElementDescriptions) { var builder = this.diagramBuilderHelper.newEdgeTool(); diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolSwitch.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolSwitch.java index 5bc4c0a21..4ef801454 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolSwitch.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewEdgeToolSwitch.java @@ -268,6 +268,7 @@ public List caseUsage(Usage object) { edgeTools.add(this.edgeToolService.createDependencyEdgeTool(targetDescriptions)); edgeTools.add(this.edgeToolService.createRedefinitionEdgeTool(List.of(this.nodeDescription))); edgeTools.add(this.edgeToolService.createSubsettingEdgeTool(List.of(this.nodeDescription))); + edgeTools.add(this.edgeToolService.createReferenceSubsettingEdgeTool(targetDescriptions)); edgeTools.add(this.edgeToolService.createAllocateEdgeTool(targetDescriptions)); var definitionNodeDescription = this.edgeToolService.getNodeDescription(this.edgeToolService.getDefinitionFromUsage(object)); if (definitionNodeDescription.isPresent()) { 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 48f4c43ce..d4237a0bf 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 @@ -77,11 +77,13 @@ import org.eclipse.syson.standard.diagrams.view.edges.InterfaceUsageEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.NestedActorEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.RedefinitionEdgeDescriptionProvider; +import org.eclipse.syson.standard.diagrams.view.edges.ReferenceSubsettingEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.SubclassificationEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.SubsettingEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.SuccessionEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.TransitionEdgeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.edges.UsageNestedUsageEdgeDescriptionProvider; +import org.eclipse.syson.standard.diagrams.view.nodes.ActionDefinitionParameterBorderNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.ActionDefinitionParametersCompartmentNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.ActionItemNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.ActionUsageParametersCompartmentNodeDescriptionProvider; @@ -98,7 +100,6 @@ import org.eclipse.syson.standard.diagrams.view.nodes.FakeNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.GeneralViewEmptyDiagramNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.nodes.InheritedPortUsageBorderNodeDescriptionProvider; -import org.eclipse.syson.standard.diagrams.view.nodes.ActionDefinitionParameterBorderNodeDescriptionProvider; 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.PortDefinitionOwnedItemBorderNodeDescriptionProvider; @@ -724,7 +725,8 @@ private List> createAllEdgeDescriptionProv edgeDescriptionProviders.add(new DependencyEdgeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); edgeDescriptionProviders.add(new SubclassificationEdgeDescriptionProvider(colorProvider)); edgeDescriptionProviders.add(new RedefinitionEdgeDescriptionProvider(colorProvider)); - edgeDescriptionProviders.add(new SubsettingEdgeDescriptionProvider(colorProvider)); + edgeDescriptionProviders.add(new SubsettingEdgeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); + edgeDescriptionProviders.add(new ReferenceSubsettingEdgeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); edgeDescriptionProviders.add(new FeatureTypingEdgeDescriptionProvider(colorProvider)); edgeDescriptionProviders.add(new AllocateEdgeDescriptionProvider(colorProvider)); edgeDescriptionProviders.add(new SuccessionEdgeDescriptionProvider(colorProvider)); diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/ReferenceSubsettingEdgeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/ReferenceSubsettingEdgeDescriptionProvider.java new file mode 100644 index 000000000..0499ba7d7 --- /dev/null +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/ReferenceSubsettingEdgeDescriptionProvider.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 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 + * 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.edges; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.generated.view.ChangeContextBuilder; +import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.diagram.ArrowStyle; +import org.eclipse.sirius.components.view.diagram.EdgeStyle; +import org.eclipse.sirius.components.view.diagram.LineStyle; +import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.syson.diagram.common.view.edges.AbstractSubsettingEdgeDescriptionProvider; +import org.eclipse.syson.standard.diagrams.view.SDVDiagramDescriptionProvider; +import org.eclipse.syson.sysml.ReferenceSubsetting; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ViewConstants; + +/** + * Used to create the {@link ReferenceSubsetting} edge description in the standard diagrams. + * + * @author arichard + */ +public class ReferenceSubsettingEdgeDescriptionProvider extends AbstractSubsettingEdgeDescriptionProvider { + + private final IDescriptionNameGenerator descriptionNameGenerator; + + public ReferenceSubsettingEdgeDescriptionProvider(IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(SysmlPackage.eINSTANCE.getReferenceSubsetting(), colorProvider); + this.descriptionNameGenerator = Objects.requireNonNull(descriptionNameGenerator); + } + + @Override + protected String getName() { + return this.descriptionNameGenerator.getEdgeName(SysmlPackage.eINSTANCE.getReferenceSubsetting()); + } + + @Override + protected String getSourceExpression() { + return AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencingFeature().getName(); + } + + @Override + protected String getTargetExpression() { + return AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName(); + } + + @Override + protected List getSourceNodes(IViewDiagramElementFinder cache) { + return this.getSourceAndTargetNodes(cache); + } + + @Override + protected List getTargetNodes(IViewDiagramElementFinder cache) { + return this.getSourceAndTargetNodes(cache); + } + + @Override + protected ChangeContextBuilder getSourceReconnectToolBody() { + var unsetOldSubsettingFeature = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewSubsettingFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var unsetOldSpecific = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewSpecific = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var setNewContainer = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getElement_OwnedRelationship().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT); + + var changeContextNewContainer = this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET) + .children(setNewContainer.build()); + + return this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT) + .children(unsetOldSubsettingFeature.build(), unsetOldSpecific.build(), setNewSubsettingFeature.build(), + setNewSpecific.build(), changeContextNewContainer.build()); + } + + @Override + protected ChangeContextBuilder getTargetReconnectToolBody() { + var unsetOldReferencedFeature = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewReferencedFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var unsetOldSubsettedFeature = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewSubsettedFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var unsetOldGeneral = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewGeneral = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + return this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT) + .children(unsetOldReferencedFeature.build(), unsetOldSubsettedFeature.build(), unsetOldGeneral.build(), setNewReferencedFeature.build(), setNewSubsettedFeature.build(), + setNewGeneral.build()); + } + + @Override + protected EdgeStyle createEdgeStyle() { + return this.diagramBuilderHelper.newEdgeStyle() + .borderSize(0) + .color(this.colorProvider.getColor(ViewConstants.DEFAULT_EDGE_COLOR)) + .edgeWidth(1) + .lineStyle(LineStyle.SOLID) + .sourceArrowStyle(ArrowStyle.NONE) + .targetArrowStyle(ArrowStyle.CLOSED_ARROW_WITH_DOTS) + .build(); + } + + private List getSourceAndTargetNodes(IViewDiagramElementFinder cache) { + var sourcesAndTargets = new ArrayList(); + + SDVDiagramDescriptionProvider.USAGES.forEach(usage -> { + cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(usage)).ifPresent(sourcesAndTargets::add); + }); + return sourcesAndTargets; + } +} diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/SubsettingEdgeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/SubsettingEdgeDescriptionProvider.java index 298bfc899..8e8bd19eb 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/SubsettingEdgeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/SubsettingEdgeDescriptionProvider.java @@ -14,39 +14,50 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.generated.view.ChangeContextBuilder; import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.diagram.ArrowStyle; +import org.eclipse.sirius.components.view.diagram.EdgeStyle; +import org.eclipse.sirius.components.view.diagram.LineStyle; import org.eclipse.sirius.components.view.diagram.NodeDescription; import org.eclipse.syson.diagram.common.view.edges.AbstractSubsettingEdgeDescriptionProvider; -import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator; import org.eclipse.syson.standard.diagrams.view.SDVDiagramDescriptionProvider; import org.eclipse.syson.sysml.Subsetting; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ViewConstants; /** - * Used to create the {@link Subsetting} edge description in the General View diagram. + * Used to create the {@link Subsetting} edge description in the standard diagrams. * * @author arichard */ public class SubsettingEdgeDescriptionProvider extends AbstractSubsettingEdgeDescriptionProvider { - public SubsettingEdgeDescriptionProvider(IColorProvider colorProvider) { - super(colorProvider); + private final IDescriptionNameGenerator descriptionNameGenerator; + + public SubsettingEdgeDescriptionProvider(IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(SysmlPackage.eINSTANCE.getSubsetting(), colorProvider); + this.descriptionNameGenerator = Objects.requireNonNull(descriptionNameGenerator); } @Override protected String getName() { - return SDVDescriptionNameGenerator.PREFIX + " Edge Subsetting"; + return this.descriptionNameGenerator.getEdgeName(SysmlPackage.eINSTANCE.getSubsetting()); } - private List getSourceAndTargetNodes(IViewDiagramElementFinder cache) { - var nameGenerator = new SDVDescriptionNameGenerator(); - var sourcesAndTargets = new ArrayList(); + @Override + protected String getSourceExpression() { + return AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName(); + } - SDVDiagramDescriptionProvider.USAGES.forEach(usage -> { - cache.getNodeDescription(nameGenerator.getNodeName(usage)).ifPresent(sourcesAndTargets::add); - }); - return sourcesAndTargets; + @Override + protected String getTargetExpression() { + return AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName(); } @Override @@ -58,4 +69,81 @@ protected List getSourceNodes(IViewDiagramElementFinder cache) protected List getTargetNodes(IViewDiagramElementFinder cache) { return this.getSourceAndTargetNodes(cache); } + + @Override + protected ChangeContextBuilder getSourceReconnectToolBody() { + var unsetOldSubsettingFeature = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewSubsettingFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettingFeature().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var unsetOldSpecific = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewSpecific = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_Specific().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var setNewContainer = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getElement_OwnedRelationship().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT); + + var changeContextNewContainer = this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET) + .children(setNewContainer.build()); + + return this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT) + .children(unsetOldSubsettingFeature.build(), unsetOldSpecific.build(), setNewSubsettingFeature.build(), + setNewSpecific.build(), changeContextNewContainer.build()); + } + + @Override + protected ChangeContextBuilder getTargetReconnectToolBody() { + var unsetOldSubsettedFeature = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewSubsettedFeature = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + var unsetOldGeneral = this.viewBuilderHelper.newUnsetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) + .elementExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_SOURCE); + + var setNewGeneral = this.viewBuilderHelper.newSetValue() + .featureName(SysmlPackage.eINSTANCE.getSpecialization_General().getName()) + .valueExpression(AQLConstants.AQL + AQLConstants.SEMANTIC_RECONNECTION_TARGET); + + return this.viewBuilderHelper.newChangeContext() + .expression(AQLConstants.AQL + AQLConstants.EDGE_SEMANTIC_ELEMENT) + .children(unsetOldSubsettedFeature.build(), unsetOldGeneral.build(), setNewSubsettedFeature.build(), + setNewGeneral.build()); + } + + @Override + protected EdgeStyle createEdgeStyle() { + return this.diagramBuilderHelper.newEdgeStyle() + .borderSize(0) + .color(this.colorProvider.getColor(ViewConstants.DEFAULT_EDGE_COLOR)) + .edgeWidth(1) + .lineStyle(LineStyle.SOLID) + .sourceArrowStyle(ArrowStyle.NONE) + .targetArrowStyle(ArrowStyle.INPUT_CLOSED_ARROW) + .build(); + } + + private List getSourceAndTargetNodes(IViewDiagramElementFinder cache) { + var sourcesAndTargets = new ArrayList(); + + SDVDiagramDescriptionProvider.USAGES.forEach(usage -> { + cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(usage)).ifPresent(sourcesAndTargets::add); + }); + return sourcesAndTargets; + } } diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.1.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.1.0.adoc index 2b2187bf6..0fa287019 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.1.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.1.0.adoc @@ -78,7 +78,7 @@ a|image::release-notes-enumeration-definition-after.png[Enumeration definition n - In diagrams, an _items_ compartment is now available on `PortDefinition` graphical nodes to display `ItemUsage`. - In diagrams, an `ItemUsage` graphical border node is now available on `PortDefinition` graphical nodes. - +- In diagrams, a new tool named `Reference Subsetting` is available in the palette to create `ReferenceSubsetting` relationships between `Usage` elements. == Technical details