diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index c061edd7a..9e1bf7f83 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -15,6 +15,7 @@ === Bug fixes - https://github.com/eclipse-syson/syson/issues/2232[#2232] [configuration] Fix a serialization problem of the View models of SysON representations. +- https://github.com/eclipse-syson/syson/issues/2237[#2237] [diagrams] Fix the item label inside `frames`, `require constraints`, and `assume constraints` compartments. === Improvements 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 423fc03af..950f281bb 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 @@ -96,11 +96,16 @@ public class DiagramQueryLabelService implements IDiagramLabelService { @Override public String getIdentificationLabel(Element element) { StringBuilder label = new StringBuilder(); + var shortNameLabel = this.getShortNameLabel(element); + String declaredName = element.getDeclaredName(); + if (element instanceof ActionUsage && element.eContainer() instanceof StateSubactionMembership ssm) { - label.append(ssm.getKind()).append(LabelConstants.SPACE); + label.append(ssm.getKind()); + if (!shortNameLabel.isBlank() || declaredName != null) { + label.append(LabelConstants.SPACE); + } } - label.append(this.getShortNameLabel(element)); - String declaredName = element.getDeclaredName(); + label.append(shortNameLabel); if (declaredName != null) { label.append(declaredName); } @@ -119,6 +124,7 @@ public String getReferenceSubsettingLabel(Element element) { 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)); @@ -549,11 +555,11 @@ public String getDependencyLabel(Dependency dependency) { } /** - * Returns the label for the given {@code dependency}. + * Returns the label for the given {@link SatisfyRequirementUsage}. * - * @param dependency - * the dependency to get the edge label from - * @return the edge label + * @param satisfyRequirementUsage + * The given {@link SatisfyRequirementUsage} + * @return the label for the given {@link SatisfyRequirementUsage} */ public String getSatisfyLabel(SatisfyRequirementUsage satisfyRequirementUsage) { StringBuilder label = new StringBuilder(); @@ -577,8 +583,19 @@ private String getCompartmentItemLabel(ConstraintUsage constraintUsage, boolean } else if (!constraintUsage.getOwnedMember().isEmpty() && constraintUsage.getOwnedMember().get(0) instanceof Expression expression) { label.append(this.getSysmlTextualRepresentation(expression, directEditInput)); } else { - // The constraint doesn't have an expression, we use its name as default label. - label.append(this.getIdentificationLabel(constraintUsage)); + var identificationLabel = this.getIdentificationLabel(constraintUsage); + if (identificationLabel.isBlank()) { + // The constraint doesn't have an expression and does not have a name, we use the referenced feature name if the referenced feature exists + var ownedReferenceSubsetting = constraintUsage.getOwnedReferenceSubsetting(); + if (ownedReferenceSubsetting != null) { + label.append(this.getIdentificationLabel(ownedReferenceSubsetting.getReferencedFeature())); + } + } else { + // The constraint doesn't have an expression and has a name, we use its name and the referenced feature name + label.append(this.getIdentificationLabel(constraintUsage)); + label.append(this.getReferenceSubsettingLabel(constraintUsage)); + } + } return label.toString(); } @@ -648,7 +665,7 @@ public String getInitialDirectEditListItemLabel(Documentation documentation) { * Get the value to display when a direct edit has been called on the given {@link Comment}. * * @param comment - * the given {@link comment}. + * the given {@link Comment}. * @return the value to display. */ public String getInitialDirectEditListItemLabel(Comment comment) { diff --git a/backend/services/syson-diagram-services/src/test/java/org/eclipse/syson/diagram/services/DiagramQueryLabelServiceTest.java b/backend/services/syson-diagram-services/src/test/java/org/eclipse/syson/diagram/services/DiagramQueryLabelServiceTest.java index 19cf66027..7e6b2c691 100644 --- a/backend/services/syson-diagram-services/src/test/java/org/eclipse/syson/diagram/services/DiagramQueryLabelServiceTest.java +++ b/backend/services/syson-diagram-services/src/test/java/org/eclipse/syson/diagram/services/DiagramQueryLabelServiceTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2025 Obeo. + * Copyright (c) 2025, 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 @@ -179,6 +179,7 @@ void testItemCompartmentLabelWithName() { } @DisplayName("Check Attribute Usage item label with name and short name") + @Test void testItemCompartmentLabelWithNameAndShortName() { AttributeUsage attributeUsage = SysmlFactory.eINSTANCE.createAttributeUsage(); attributeUsage.setDeclaredName(ATTRIBUTE_USAGE_NAME); @@ -270,9 +271,9 @@ void testItemCompartmentLabelWithPrefixAndMultiplicity() { this.labelService.getCompartmentItemLabel(attributeUsage)); } - @DisplayName("GIVEN a ConstraintUsage with no expression, WHEN its label is computed, THEN the label contains the name of the constraint") + @DisplayName("GIVEN a ConstraintUsage without expression, with declared name, without requiring another constraint, WHEN its label is computed, THEN the label contains the name of the constraint") @Test - public void testGetCompartmentItemLabelOfConstraintWithNoExpression() { + public void testGetCompartmentItemLabelOfConstraintWithoutExpressionWithDeclaredNameWithoutRequiringAnotherConstraint() { ConstraintUsage constraintUsage = SysmlFactory.eINSTANCE.createConstraintUsage(); constraintUsage.setDeclaredName(CONSTRAINT_USAGE_NAME); // Constraints have a special label when they are inside a RequirementConstraintMembership @@ -281,6 +282,41 @@ public void testGetCompartmentItemLabelOfConstraintWithNoExpression() { assertThat(this.labelService.getCompartmentItemLabel(constraintUsage)).isEqualTo(CONSTRAINT_USAGE_NAME); } + @DisplayName("GIVEN a ConstraintUsage without expression, with declared name, requiring another constraint, WHEN its label is computed, THEN the label contains the constraint name with subsetted refence name") + @Test + public void testGetCompartmentItemLabelOfConstraintWithoutExpressionWithDeclaredNameRequiringAnotherConstraint() { + ConstraintUsage constraintUsage = SysmlFactory.eINSTANCE.createConstraintUsage(); + constraintUsage.setDeclaredName(CONSTRAINT_USAGE_NAME); + + ConstraintUsage referenceConstraintUsage = SysmlFactory.eINSTANCE.createConstraintUsage(); + referenceConstraintUsage.setDeclaredName("referencedConstraint"); + var referenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting(); + referenceSubsetting.setReferencedFeature(referenceConstraintUsage); + constraintUsage.getOwnedRelationship().add(referenceSubsetting); + + // Constraints have a special label when they are inside a RequirementConstraintMembership + RequirementConstraintMembership requirementConstraintMembership = SysmlFactory.eINSTANCE.createRequirementConstraintMembership(); + requirementConstraintMembership.getOwnedRelatedElement().add(constraintUsage); + assertThat(this.labelService.getCompartmentItemLabel(constraintUsage)).isEqualTo(CONSTRAINT_USAGE_NAME + LabelConstants.SPACE + LabelConstants.REFERENCES + LabelConstants.SPACE + "referencedConstraint"); + } + + @DisplayName("GIVEN a ConstraintUsage without expression, without declared name, requiring another constraint, WHEN its label is computed, THEN the label contains only subsetted refence name") + @Test + public void testGetCompartmentItemLabelOfConstraintWithoutExpressionWithoutDeclaredNameRequiringAnotherConstraint() { + ConstraintUsage constraintUsage = SysmlFactory.eINSTANCE.createConstraintUsage(); + + ConstraintUsage referenceConstraintUsage = SysmlFactory.eINSTANCE.createConstraintUsage(); + referenceConstraintUsage.setDeclaredName("referencedConstraint"); + var referenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting(); + referenceSubsetting.setReferencedFeature(referenceConstraintUsage); + constraintUsage.getOwnedRelationship().add(referenceSubsetting); + + // Constraints have a special label when they are inside a RequirementConstraintMembership + RequirementConstraintMembership requirementConstraintMembership = SysmlFactory.eINSTANCE.createRequirementConstraintMembership(); + requirementConstraintMembership.getOwnedRelatedElement().add(constraintUsage); + assertThat(this.labelService.getCompartmentItemLabel(constraintUsage)).isEqualTo("referencedConstraint"); + } + @DisplayName("GIVEN a ConstraintUsage with a boolean expression, WHEN its label is computed, THEN the label represents the expression") @Test public void testGetCompartmentItemLabelOfConstraintWithBooleanExpression() { 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 43d631a77..b875607ef 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 @@ -51,6 +51,12 @@ a|image::explorer-expression-internals-visible.png[Internals visible] ** Improve diagram-to-diagram drag and drop to support dropping multiple graphical nodes at once. ** Improve feedback message reporting while moving elements in diagrams. +** Fix and improve the labeling logic inside `frames`, `require constraints`, and `assume constraints` compartments. +Previously, the label was always the name of the `ConcernUsage` or the `ConstraintUsage` displayed in the compartment. +Now, the label dynamically adapts based on whether the `ConcernUsage` or `ConstraintUsage` has a name and an owned reference subsetting: +*** Elements having both a name and an owned reference subsetting now display using the standard subsetting notation (e.g., `ElementName ::> SubsettingName`). +*** Elements without name and an owned reference subsetting display only the reference subsetting name +*** Elements without reference subsetting display their name. == Technical details