From bbd1f74891173266f23a7b94f3b0e783a1b59621 Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Wed, 24 Apr 2024 17:10:43 +0200 Subject: [PATCH] [242] Handle Inherited features in features compartments Bug: https://github.com/eclipse-syson/syson/issues/242 Signed-off-by: Axel RICHARD --- CHANGELOG.adoc | 1 + .../services/CoreFeaturesSwitch.java | 9 ++ .../syson/sysml/impl/DefinitionImpl.java | 20 ++++ .../sysml/impl/FeatureMembershipImpl.java | 16 ++-- .../eclipse/syson/sysml/impl/TypeImpl.java | 27 ++++-- .../eclipse/syson/sysml/impl/UsageImpl.java | 21 +++++ .../syson/util/DescriptionNameGenerator.java | 38 ++++++-- .../syson/util/IDescriptionNameGenerator.java | 14 ++- .../syson/tests/GitCommitMessageTests.java | 5 - ...actCompartmentNodeDescriptionProvider.java | 2 + ...ompartmentItemNodeDescriptionProvider.java | 91 +++++++++++++++++++ .../InheritedCompartmentItemFilterSwitch.java | 68 ++++++++++++++ .../view/services/ViewCreateService.java | 48 ++++++++++ ...GeneralViewDiagramDescriptionProvider.java | 2 + .../view/GeneralViewJavaServiceProvider.java | 4 +- .../view/services/GeneralViewEdgeService.java | 6 +- 16 files changed, 336 insertions(+), 36 deletions(-) create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedCompartmentItemNodeDescriptionProvider.java create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/InheritedCompartmentItemFilterSwitch.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index e9bbe074d..b6c01f9f8 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -49,6 +49,7 @@ - https://github.com/eclipse-syson/syson/issues/219[#219] [diagrams] Handle ConjugatedPortDefinition in diagrams, Explorer and Details View. - https://github.com/eclipse-syson/syson/issues/234[#234] [interconnection-view] Handle InterfaceUsages edges between PortUsages in InterconnectionView. - https://github.com/eclipse-syson/syson/issues/175[#175] [diagrams] Add the State Transition view diagram +- https://github.com/eclipse-syson/syson/issues/242[#242] [diagrams] Handle Inherited features in features compartments. == v2024.3.0 diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/CoreFeaturesSwitch.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/CoreFeaturesSwitch.java index 16f2886ae..2001a797d 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/CoreFeaturesSwitch.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/services/CoreFeaturesSwitch.java @@ -34,6 +34,7 @@ import org.eclipse.syson.sysml.PortUsage; import org.eclipse.syson.sysml.Redefinition; import org.eclipse.syson.sysml.ReferenceSubsetting; +import org.eclipse.syson.sysml.RequirementConstraintMembership; import org.eclipse.syson.sysml.Specialization; import org.eclipse.syson.sysml.Subclassification; import org.eclipse.syson.sysml.Subsetting; @@ -195,6 +196,14 @@ public List caseReferenceSubsetting(ReferenceSubsetting obje return features; } + @Override + public List caseRequirementConstraintMembership(RequirementConstraintMembership object) { + var features = new ArrayList(); + features.add(SysmlPackage.eINSTANCE.getMembership_Visibility()); + features.add(SysmlPackage.eINSTANCE.getRequirementConstraintMembership_Kind()); + return features; + } + @Override public List caseSpecialization(Specialization object) { var features = new ArrayList(); diff --git a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/DefinitionImpl.java b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/DefinitionImpl.java index 46de83415..22cd241b8 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/DefinitionImpl.java +++ b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/DefinitionImpl.java @@ -35,6 +35,7 @@ import org.eclipse.syson.sysml.FlowConnectionUsage; import org.eclipse.syson.sysml.InterfaceUsage; import org.eclipse.syson.sysml.ItemUsage; +import org.eclipse.syson.sysml.Membership; import org.eclipse.syson.sysml.MetadataUsage; import org.eclipse.syson.sysml.OccurrenceUsage; import org.eclipse.syson.sysml.PartUsage; @@ -45,6 +46,7 @@ import org.eclipse.syson.sysml.StateUsage; import org.eclipse.syson.sysml.SysmlPackage; import org.eclipse.syson.sysml.TransitionUsage; +import org.eclipse.syson.sysml.Type; import org.eclipse.syson.sysml.Usage; import org.eclipse.syson.sysml.UseCaseUsage; import org.eclipse.syson.sysml.VariantMembership; @@ -689,6 +691,24 @@ public EList getVariantMembership() { return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getDefinition_VariantMembership(), data.size(), data.toArray()); } + /** + * + * + * @generated NOT + */ + @Override + public EList getInheritedMembership() { + List inheritedMemberships = new ArrayList<>(); + this.getOwnedSpecialization().forEach(spe -> { + Type general = spe.getGeneral(); + if (general != null) { + inheritedMemberships.addAll(general.getInheritedMembership()); + inheritedMemberships.addAll(general.getOwnedMembership()); + } + }); + return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_InheritedMembership(), inheritedMemberships.size(), inheritedMemberships.toArray()); + } + /** * * diff --git a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureMembershipImpl.java b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureMembershipImpl.java index 21b5a48cd..e36fed946 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureMembershipImpl.java +++ b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureMembershipImpl.java @@ -16,7 +16,9 @@ import java.util.Optional; import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.syson.sysml.Feature; @@ -181,15 +183,11 @@ public Feature getOwnedMemberFeature() { * @generated NOT */ public Feature basicGetOwnedMemberFeature() { - Optional optionalFM = this.getOwnedRelationship().stream() - .filter(FeatureMembership.class::isInstance) - .map(FeatureMembership.class::cast) - .filter(fm -> fm.getOwnedMemberFeature() != null) - .findFirst(); - if (optionalFM.isPresent()) { - return optionalFM.get().getOwnedMemberFeature(); - } - return null; + return this.getOwnedRelatedElement().stream() + .filter(Feature.class::isInstance) + .map(Feature.class::cast) + .findFirst() + .orElse(null); } /** diff --git a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/TypeImpl.java b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/TypeImpl.java index 04d4176ce..b8f5d0c7b 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/TypeImpl.java +++ b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/TypeImpl.java @@ -22,7 +22,7 @@ import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.util.EcoreEList; -import org.eclipse.syson.sysml.AttributeUsage; +import org.eclipse.syson.sysml.Classifier; import org.eclipse.syson.sysml.Conjugation; import org.eclipse.syson.sysml.Differencing; import org.eclipse.syson.sysml.Disjoining; @@ -205,19 +205,27 @@ public EList getFeatureMembership() { */ @Override public EList getInheritedFeature() { - List data = new ArrayList<>(); - return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_InheritedFeature(), data.size(), data.toArray()); + List inheritedFeatures = new ArrayList<>(); + this.getInheritedMembership().stream() + .filter(FeatureMembership.class::isInstance) + .map(FeatureMembership.class::cast) + .map(FeatureMembership::getOwnedMemberFeature) + .forEach(inheritedFeatures::add); + return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_InheritedFeature(), inheritedFeatures.size(), inheritedFeatures.toArray()); } /** * + * Partial implementation (see sub types, e.g. UsageImpl or DefinitionImpl). Should be: + * All Memberships inherited by this Type via Specialization or Conjugation. + * These are included in the derived union for the memberships of the Type. * * @generated NOT */ @Override public EList getInheritedMembership() { - List data = new ArrayList<>(); - return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_InheritedMembership(), data.size(), data.toArray()); + List inheritedMemberships = new ArrayList<>(); + return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_InheritedMembership(), inheritedMemberships.size(), inheritedMemberships.toArray()); } /** @@ -395,8 +403,11 @@ public EList getOwnedEndFeature() { */ @Override public EList getOwnedFeature() { - List data = new ArrayList<>(); - return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_OwnedFeature(), data.size(), data.toArray()); + List ownedFeatures = new ArrayList<>(); + this.getOwnedFeatureMembership().stream() + .map(FeatureMembership::getOwnedMemberFeature) + .forEach(ownedFeatures::add); + return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_OwnedFeature(), ownedFeatures.size(), ownedFeatures.toArray()); } /** @@ -433,7 +444,7 @@ public EList getOwnedIntersecting() { @Override public EList getOwnedSpecialization() { List ownedSpecializations = new ArrayList<>(); - // The ownedRelationships of this Type that are Specializations, for which the Type is the specific Type. + // The ownedRelationships of this Type that are Specializations, and for which the Specialization's specific Type is this Type. this.getOwnedRelationship().stream() .filter(Specialization.class::isInstance) .map(Specialization.class::cast) diff --git a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/UsageImpl.java b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/UsageImpl.java index a747a4028..09fb9466a 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/UsageImpl.java +++ b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/UsageImpl.java @@ -169,6 +169,27 @@ public EList getDefinition() { return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getUsage_Definition(), definitions.size(), definitions.toArray()); } + /** + * + * + * @generated NOT + */ + @Override + public EList getInheritedMembership() { + List inheritedMemberships = new ArrayList<>(); + this.getDefinition().forEach(def -> { + inheritedMemberships.addAll(def.getInheritedMembership()); + inheritedMemberships.addAll(def.getOwnedMembership()); + }); + Usage owningUsage = this.getOwningUsage(); + if (owningUsage != null) { + inheritedMemberships.addAll(owningUsage.getInheritedMembership()); + inheritedMemberships.addAll(owningUsage.getOwnedMembership()); + } + List distinctInheritedMemberships = inheritedMemberships.stream().distinct().toList(); + return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getType_InheritedMembership(), distinctInheritedMemberships.size(), distinctInheritedMemberships.toArray()); + } + /** * * diff --git a/backend/services/syson-services/src/main/java/org/eclipse/syson/util/DescriptionNameGenerator.java b/backend/services/syson-services/src/main/java/org/eclipse/syson/util/DescriptionNameGenerator.java index 301c62504..5aa47a9e5 100644 --- a/backend/services/syson-services/src/main/java/org/eclipse/syson/util/DescriptionNameGenerator.java +++ b/backend/services/syson-services/src/main/java/org/eclipse/syson/util/DescriptionNameGenerator.java @@ -31,6 +31,8 @@ */ public class DescriptionNameGenerator implements IDescriptionNameGenerator { + private static final String SPACE = " "; + private static final Pattern WORD_FINDER = Pattern.compile("(([A-Z]?[a-z]+)|([A-Z]))"); private final String diagramPrefix; @@ -41,7 +43,7 @@ public DescriptionNameGenerator(String diagramPrefix) { protected String getName(String prefix, String descType, String type) { StringBuilder name = new StringBuilder(); - name.append(prefix).append(" ").append(descType).append(" ").append(type); + name.append(prefix).append(SPACE).append(descType).append(SPACE).append(type); return name.toString(); } @@ -53,12 +55,16 @@ protected String getBorderNodeName(String prefix, String type) { return this.getName(prefix, "BorderNode", type); } - protected String getCompartmentName(String prefix, String type) { - return this.getName(prefix, "Compartment", type); + protected String getCompartmentName(String prefix, String suffix) { + return this.getName(prefix, "Compartment", suffix); + } + + protected String getCompartmentItemName(String prefix, String suffix) { + return this.getName(prefix, "CompartmentItem", suffix); } - protected String getCompartmentItemName(String prefix, String type) { - return this.getName(prefix, "CompartmentItem", type); + protected String getInheritedCompartmentItemName(String prefix, String suffix) { + return this.getName(prefix, "InheritedCompartmentItem", suffix); } protected String getEdgeName(String prefix, String type) { @@ -88,7 +94,7 @@ public String getCreationToolName(String prefix, EClassifier eClassifier) { } } } - return prefix + this.findWordsInMixedCase(nameToParse).stream().collect(Collectors.joining(" ")); + return prefix + this.findWordsInMixedCase(nameToParse).stream().collect(Collectors.joining(SPACE)); } private List findWordsInMixedCase(String text) { @@ -176,7 +182,7 @@ public String getBorderNodeName(EClass eClass) { */ @Override public String getCompartmentName(EClass eClass, EReference eReference) { - return this.getCompartmentName(this.diagramPrefix, eClass.getName() + " " + eReference.getName()); + return this.getCompartmentName(this.diagramPrefix, eClass.getName() + SPACE + eReference.getName()); } /** @@ -192,7 +198,23 @@ public String getCompartmentName(EClass eClass, EReference eReference) { */ @Override public String getCompartmentItemName(EClass eClass, EReference eReference) { - return this.getCompartmentItemName(this.diagramPrefix, eClass.getName() + " " + eReference.getName()); + return this.getCompartmentItemName(this.diagramPrefix, eClass.getName() + SPACE + eReference.getName()); + } + + /** + * Returns the name of the inherited compartment item {@link NodeDescription} starting with the diagram prefix, + * followed by the name of the given {@link EClass} and the name of the given {@link EReference}. + * + * @param eClass + * the {@link EClass} used to compute the name of the {@link NodeDescription}. + * @param eReference + * the {@link EReference} that the compartment is containing. + * @return a string starting with the diagram prefix, followed by the name of the given {@link EClass} and the name + * of the given {@link EReference} + */ + @Override + public String getInheritedCompartmentItemName(EClass eClass, EReference eReference) { + return this.getInheritedCompartmentItemName(this.diagramPrefix, eClass.getName() + SPACE + eReference.getName()); } /** diff --git a/backend/services/syson-services/src/main/java/org/eclipse/syson/util/IDescriptionNameGenerator.java b/backend/services/syson-services/src/main/java/org/eclipse/syson/util/IDescriptionNameGenerator.java index 34471c7d7..3293535ad 100644 --- a/backend/services/syson-services/src/main/java/org/eclipse/syson/util/IDescriptionNameGenerator.java +++ b/backend/services/syson-services/src/main/java/org/eclipse/syson/util/IDescriptionNameGenerator.java @@ -112,10 +112,22 @@ default String getCreationToolName(EReference eReference) { * the {@link EClass} used to compute the name of the {@link NodeDescription}. * @param eReference * the {@link EReference} that the compartment is containing. - * @return a string used to name a compartment items {@link NodeDescription}. + * @return a string used to name a compartment item {@link NodeDescription}. */ String getCompartmentItemName(EClass eClass, EReference eReference); + /** + * Returns the name of an inherited compartment item {@link NodeDescription} using the given {@link EClass} and + * {@link EReference}. + * + * @param eClass + * the {@link EClass} used to compute the name of the {@link NodeDescription}. + * @param eReference + * the {@link EReference} that the compartment is containing. + * @return a string used to name an inherited compartment item {@link NodeDescription}. + */ + String getInheritedCompartmentItemName(EClass eClass, EReference eReference); + /** * Returns the name of a domain based {@link EdgeDescription} using given the given {@link EClass}. * diff --git a/backend/tests/syson-tests/src/test/java/org/eclipse/syson/tests/GitCommitMessageTests.java b/backend/tests/syson-tests/src/test/java/org/eclipse/syson/tests/GitCommitMessageTests.java index f8711f4d1..101587e46 100644 --- a/backend/tests/syson-tests/src/test/java/org/eclipse/syson/tests/GitCommitMessageTests.java +++ b/backend/tests/syson-tests/src/test/java/org/eclipse/syson/tests/GitCommitMessageTests.java @@ -55,7 +55,6 @@ private List runCommand() { try { Process process = Runtime.getRuntime().exec(GIT_COMMAND); - // @formatter:off try ( BufferedReader lineReader = new BufferedReader(new InputStreamReader(process.getInputStream())); BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); @@ -63,7 +62,6 @@ private List runCommand() { lines = lineReader.lines().collect(Collectors.toList()); assertThat(errorReader.lines()).isEmpty(); } - // @formatter:on } catch (IOException exception) { fail(exception.getMessage()); } @@ -126,13 +124,10 @@ public void testTitle() { if (!KEYWORDS.contains(tag)) { try { Integer.valueOf(tag); - - // @formatter:off assertThat(lines) .withFailMessage(MISSING_ISSUE_URL_FOOTER) .filteredOn(line -> line.trim().startsWith(ISSUE_URL_PREFIX) && line.endsWith(tag)) .hasSize(1); - // @formatter:on } catch (NumberFormatException exception) { fail(INVALID_GIT_MESSAGE_TITLE); } diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractCompartmentNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractCompartmentNodeDescriptionProvider.java index 406a35d00..ba480a514 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractCompartmentNodeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractCompartmentNodeDescriptionProvider.java @@ -104,6 +104,8 @@ public NodeDescription create() { @Override public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { cache.getNodeDescription(this.nameGenerator.getCompartmentName(this.eClass, this.eReference)).ifPresent(nodeDescription -> { + cache.getNodeDescription(this.nameGenerator.getInheritedCompartmentItemName(this.eClass, this.eReference)) + .ifPresent(node -> nodeDescription.getChildrenDescriptions().add(node)); cache.getNodeDescription(this.nameGenerator.getCompartmentItemName(this.eClass, this.eReference)) .ifPresent(node -> nodeDescription.getChildrenDescriptions().add(node)); nodeDescription.setPalette(this.createCompartmentPalette(cache)); diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedCompartmentItemNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedCompartmentItemNodeDescriptionProvider.java new file mode 100644 index 000000000..ab2c64fed --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedCompartmentItemNodeDescriptionProvider.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2024 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.diagram.common.view.nodes; + +import java.util.Objects; + +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.InsideLabelDescription; +import org.eclipse.sirius.components.view.diagram.InsideLabelPosition; +import org.eclipse.sirius.components.view.diagram.InsideLabelStyle; +import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.sirius.components.view.diagram.NodeStyleDescription; +import org.eclipse.sirius.components.view.diagram.SynchronizationPolicy; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.SysMLMetamodelHelper; +import org.eclipse.syson.util.ViewConstants; + +/** + * Used to create the inherited compartment item node description. + * + * @author arichard + */ +public class InheritedCompartmentItemNodeDescriptionProvider extends AbstractNodeDescriptionProvider { + + private final EClass eClass; + + private final EReference eReference; + + private final IDescriptionNameGenerator nameGenerator; + + public InheritedCompartmentItemNodeDescriptionProvider(EClass eClass, EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator nameGenerator) { + super(colorProvider); + this.eClass = Objects.requireNonNull(eClass); + this.eReference = Objects.requireNonNull(eReference); + this.nameGenerator = Objects.requireNonNull(nameGenerator); + } + + @Override + public NodeDescription create() { + return this.diagramBuilderHelper.newNodeDescription() + .defaultHeightExpression(ViewConstants.DEFAULT_COMPARTMENT_NODE_ITEM_HEIGHT) + .defaultWidthExpression(ViewConstants.DEFAULT_NODE_WIDTH) + .domainType(SysMLMetamodelHelper.buildQualifiedName(this.eReference.getEType())) + .insideLabel(this.createInsideLabelDescription()) + .name(this.nameGenerator.getInheritedCompartmentItemName(this.eClass, this.eReference)) + .semanticCandidatesExpression(AQLConstants.AQL_SELF + ".getInheritedCompartmentItems('" + this.eReference.getName() + "')") + .style(this.createCompartmentItemNodeStyle()) + .userResizable(false) + .synchronizationPolicy(SynchronizationPolicy.SYNCHRONIZED) + .build(); + } + + protected InsideLabelDescription createInsideLabelDescription() { + return this.diagramBuilderHelper.newInsideLabelDescription() + .labelExpression(AQLConstants.AQL + "'^' + self.getCompartmentItemUsageLabel()") + .position(InsideLabelPosition.TOP_CENTER) + .style(this.createInsideLabelStyle()) + .build(); + } + + protected InsideLabelStyle createInsideLabelStyle() { + return this.diagramBuilderHelper.newInsideLabelStyle() + .displayHeaderSeparator(false) + .italic(true) + .labelColor(this.colorProvider.getColor(ViewConstants.DEFAULT_LABEL_COLOR)) + .showIcon(true) + .withHeader(false) + .build(); + } + + private NodeStyleDescription createCompartmentItemNodeStyle() { + return this.diagramBuilderHelper.newIconLabelNodeStyleDescription() + .borderColor(this.colorProvider.getColor(ViewConstants.DEFAULT_BORDER_COLOR)) + .borderRadius(0) + .color(this.colorProvider.getColor(ViewConstants.DEFAULT_BACKGROUND_COLOR)) + .build(); + } +} 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 new file mode 100644 index 000000000..ea1ef6272 --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/InheritedCompartmentItemFilterSwitch.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2024 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.diagram.common.view.services; + +import java.util.Objects; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.syson.sysml.ConstraintUsage; +import org.eclipse.syson.sysml.Feature; +import org.eclipse.syson.sysml.OwningMembership; +import org.eclipse.syson.sysml.RequirementConstraintKind; +import org.eclipse.syson.sysml.RequirementConstraintMembership; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.sysml.util.SysmlSwitch; + +/** + * Test. + * + * @author arichard + */ +public class InheritedCompartmentItemFilterSwitch extends SysmlSwitch { + + private final EReference eReference; + + public InheritedCompartmentItemFilterSwitch(EReference eReference) { + this.eReference = Objects.requireNonNull(eReference); + } + + @Override + public Boolean defaultCase(EObject object) { + return false; + } + + @Override + public Boolean caseFeature(Feature object) { + return this.eReference.getEType().equals(object.eClass()); + } + + @Override + public Boolean caseConstraintUsage(ConstraintUsage object) { + boolean keep = true; + OwningMembership owningMembership = object.getOwningMembership(); + if (owningMembership instanceof RequirementConstraintMembership constraintMembership) { + RequirementConstraintKind constraintKind = constraintMembership.getKind(); + if (SysmlPackage.eINSTANCE.getRequirementDefinition_AssumedConstraint().equals(this.eReference)) { + keep = RequirementConstraintKind.ASSUMPTION == constraintKind; + } else if (SysmlPackage.eINSTANCE.getRequirementDefinition_RequiredConstraint().equals(this.eReference)) { + keep = RequirementConstraintKind.REQUIREMENT == constraintKind; + } else if (SysmlPackage.eINSTANCE.getRequirementUsage_AssumedConstraint().equals(this.eReference)) { + keep = RequirementConstraintKind.ASSUMPTION == constraintKind; + } else if (SysmlPackage.eINSTANCE.getRequirementUsage_RequiredConstraint().equals(this.eReference)) { + keep = RequirementConstraintKind.REQUIREMENT == constraintKind; + } + } + return keep && this.caseFeature(object); + } +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java index 501f2f081..d49c2395d 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/services/ViewCreateService.java @@ -12,10 +12,12 @@ *******************************************************************************/ package org.eclipse.syson.diagram.common.view.services; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramContext; import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramService; @@ -29,6 +31,7 @@ import org.eclipse.syson.sysml.AllocationDefinition; import org.eclipse.syson.sysml.AllocationUsage; import org.eclipse.syson.sysml.Element; +import org.eclipse.syson.sysml.Feature; import org.eclipse.syson.sysml.FeatureMembership; import org.eclipse.syson.sysml.Membership; import org.eclipse.syson.sysml.ObjectiveMembership; @@ -39,9 +42,11 @@ import org.eclipse.syson.sysml.RequirementConstraintMembership; import org.eclipse.syson.sysml.RequirementDefinition; import org.eclipse.syson.sysml.RequirementUsage; +import org.eclipse.syson.sysml.Specialization; import org.eclipse.syson.sysml.SubjectMembership; import org.eclipse.syson.sysml.SysmlFactory; import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.sysml.Type; import org.eclipse.syson.sysml.Usage; import org.eclipse.syson.sysml.UseCaseDefinition; import org.eclipse.syson.sysml.UseCaseUsage; @@ -349,4 +354,47 @@ private Element getSourceOwner(Node sourceNode, IEditingContext editingContext, .map(Element.class::cast) .orElse(null); } + + public List getInheritedCompartmentItems(Type type, String eReferenceName) { + List inheritedElements = new ArrayList<>(); + EStructuralFeature eStructuralFeature = type.eClass().getEStructuralFeature(eReferenceName); + if (eStructuralFeature instanceof EReference eReference) { + type.getInheritedFeature().stream() + .filter(feature -> new InheritedCompartmentItemFilterSwitch(eReference).doSwitch(feature)) + .forEach(inheritedElements::add); + } + // Removes all features that have been redefined, subsetted, subclassed... + List alreadySpecializedFeatures = new ArrayList<>(); + type.getOwnedFeature().stream() + .flatMap(f -> this.getSpecializationTypeHierarchy(f).stream()) + .filter(general -> inheritedElements.contains(general)) + .forEach(alreadySpecializedFeatures::add); + inheritedElements.stream() + .flatMap(f -> this.getSpecializationTypeHierarchy(f).stream()) + .filter(general -> inheritedElements.contains(general)) + .forEach(alreadySpecializedFeatures::add); + inheritedElements.removeAll(alreadySpecializedFeatures); + return inheritedElements; + } + + private List getSpecializationTypeHierarchy(Type type) { + List specializationTypeHierarchy = new ArrayList<>(); + this.getSpecializationTypeHierarchy(type, specializationTypeHierarchy); + return specializationTypeHierarchy; + } + + private void getSpecializationTypeHierarchy(Type type, List specializationTypeHierarchy) { + List specializationTypes = new ArrayList<>(); + type.getOwnedSpecialization().stream() + .map(Specialization::getGeneral) + .forEach(general -> { + if (!specializationTypeHierarchy.contains(general) && !specializationTypes.contains(general)) { + specializationTypes.add(general); + specializationTypeHierarchy.add(general); + } + }); + specializationTypes.forEach(speType -> { + this.getSpecializationTypeHierarchy(speType, specializationTypeHierarchy); + }); + } } diff --git a/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewDiagramDescriptionProvider.java b/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewDiagramDescriptionProvider.java index 74ab4dd24..65c60d559 100644 --- a/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewDiagramDescriptionProvider.java +++ b/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewDiagramDescriptionProvider.java @@ -32,6 +32,7 @@ import org.eclipse.syson.diagram.common.view.ViewDiagramElementFinder; import org.eclipse.syson.diagram.common.view.diagram.AbstractDiagramDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.CompartmentItemNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.InheritedCompartmentItemNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.tools.ToolSectionDescription; import org.eclipse.syson.diagram.general.view.edges.AllocateEdgeDescriptionProvider; import org.eclipse.syson.diagram.general.view.edges.DefinitionOwnedUsageEdgeDescriptionProvider; @@ -235,6 +236,7 @@ public RepresentationDescription create(IColorProvider colorProvider) { COMPARTMENTS_WITH_LIST_ITEMS.forEach((eClass, listItems) -> { listItems.forEach(eReference -> { diagramElementDescriptionProviders.add(new CompartmentNodeDescriptionProvider(eClass, eReference, colorProvider)); + diagramElementDescriptionProviders.add(new InheritedCompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.nameGenerator)); diagramElementDescriptionProviders.add(new CompartmentItemNodeDescriptionProvider(eClass, eReference, colorProvider, this.nameGenerator)); }); }); diff --git a/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewJavaServiceProvider.java b/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewJavaServiceProvider.java index e77765445..d28a3e6d9 100644 --- a/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewJavaServiceProvider.java +++ b/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/GeneralViewJavaServiceProvider.java @@ -16,7 +16,6 @@ import org.eclipse.sirius.components.view.View; import org.eclipse.sirius.components.view.emf.IJavaServiceProvider; -import org.eclipse.syson.diagram.common.view.services.ViewEdgeService; import org.eclipse.syson.diagram.common.view.services.ViewLabelService; import org.eclipse.syson.diagram.common.view.services.ViewToolService; import org.eclipse.syson.diagram.general.view.services.GeneralViewCreateService; @@ -45,8 +44,7 @@ public List> getServiceClasses(View view) { GeneralViewEdgeService.class, ViewLabelService.class, ViewToolService.class, - UtilService.class, - ViewEdgeService.class); + UtilService.class); } return List.of(); } diff --git a/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/services/GeneralViewEdgeService.java b/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/services/GeneralViewEdgeService.java index 6525e81b4..cc37d560a 100644 --- a/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/services/GeneralViewEdgeService.java +++ b/backend/views/syson-diagram-general-view/src/main/java/org/eclipse/syson/diagram/general/view/services/GeneralViewEdgeService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Obeo. + * Copyright (c) 2023, 2024 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 @@ -17,6 +17,7 @@ import org.eclipse.sirius.components.core.api.IFeedbackMessageService; import org.eclipse.sirius.components.representations.Message; import org.eclipse.sirius.components.representations.MessageLevel; +import org.eclipse.syson.diagram.common.view.services.ViewEdgeService; import org.eclipse.syson.diagram.general.view.GeneralViewDiagramDescriptionProvider; import org.eclipse.syson.sysml.AttributeDefinition; import org.eclipse.syson.sysml.AttributeUsage; @@ -35,11 +36,12 @@ * * @author arichard */ -public class GeneralViewEdgeService { +public class GeneralViewEdgeService extends ViewEdgeService { private final IFeedbackMessageService feedbackMessageService; public GeneralViewEdgeService(IFeedbackMessageService feedbackMessageService) { + super(); this.feedbackMessageService = Objects.requireNonNull(feedbackMessageService); }