From 8bf4144a7f4ceca40e6e0a2784ab0da42ff471c8 Mon Sep 17 00:00:00 2001 From: Guillaume Coutable Date: Fri, 14 Aug 2026 20:26:37 +0200 Subject: [PATCH] [2403] Add the support for ActionDefinition and ActionUsage ItemUsage inherited border nodes Bug: https://github.com/eclipse-syson/syson/issues/2403 Signed-off-by: Guillaume Coutable --- CHANGELOG.adoc | 1 + .../general/view/GVFlowUsageTests.java | 2 + .../GVCompartmentItemInheritanceTests.java | 10 +- ...temUsageBorderNodeDescriptionProvider.java | 154 ++++++++++++++++++ .../AbstractNodeDescriptionProvider.java | 2 + ...temUsageBorderNodeDescriptionProvider.java | 78 +++++++++ ...temUsageBorderNodeDescriptionProvider.java | 121 ++------------ .../view/SDVDiagramDescriptionProvider.java | 3 + ...nnectorAsUsageEdgeDescriptionProvider.java | 2 + .../FeatureValueEdgeDescriptionProvider.java | 2 + .../FlowUsageEdgeDescriptionProvider.java | 2 + .../DefinitionNodeDescriptionProvider.java | 1 + .../nodes/FakeNodeDescriptionProvider.java | 4 + .../nodes/UsageNodeDescriptionProvider.java | 1 + ...tes-action-inherited-item-border-nodes.png | Bin 0 -> 22637 bytes .../pages/release-notes/2026.9.0.adoc | 4 +- 16 files changed, 274 insertions(+), 113 deletions(-) create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractItemUsageBorderNodeDescriptionProvider.java create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedItemUsageBorderNodeDescriptionProvider.java create mode 100644 doc/content/modules/user-manual/assets/images/release-notes-action-inherited-item-border-nodes.png diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 4e6674df4b..db32eba6f0 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -81,6 +81,7 @@ It is also now possible to create new concerns using the _New Concern_ tool from - https://github.com/eclipse-syson/syson/issues/2397[#2397] [diagrams] Display existing binary requirement derivations as edges in the _General View_. A requirement derivation is a `ConnectionUsage` annotated with the `#derivation` metadata or typed by `DerivationConnections::Derivation`. The edge goes from the derived requirement to the original one and is displayed as a dashed `«derive»` line, so it can be distinguished from a `«satisfy»` edge. +- https://github.com/eclipse-syson/syson/issues/2403[#2403] [diagrams] Add support for the inheritance of `ItemUsage` border nodes on `ActionDefinition` and `ActionUsage` graphical nodes. == v2026.7.0 diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVFlowUsageTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVFlowUsageTests.java index 1da41de736..e47139daa4 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVFlowUsageTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVFlowUsageTests.java @@ -685,6 +685,8 @@ private List getExpectedFlowTargetDescriptionNames() { this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort()), this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem()), this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem()), + this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem()), + this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem()), this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage()), this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())); } diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/inheritance/GVCompartmentItemInheritanceTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/inheritance/GVCompartmentItemInheritanceTests.java index 65d1649e80..d1ed0c51dc 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/inheritance/GVCompartmentItemInheritanceTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/inheritance/GVCompartmentItemInheritanceTests.java @@ -188,11 +188,11 @@ private static Stream actionsCompartmentItemInheritanceArguments() { private static Stream itemsCompartmentItemInheritanceArguments() { NestedElementTestArgument nestedItemWithBorderNode = new NestedElementTestArgument("New Item", "items", "item1", "", 1, 1, 0); return Stream.of( - Arguments.of(ACTION_DEFINITION_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, FEATURE_TYPING_ARGUMENT), - Arguments.of(ACTION_DEFINITION_ARGUMENT, nestedItemWithBorderNode, ACTION_DEFINITION_ARGUMENT, SUBCLASSIFICATION_ARGUMENT), - Arguments.of(ACTION_USAGE_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, SUBSETTING_ARGUMENT), - Arguments.of(ACTION_USAGE_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, REFERENCE_SUBSETTING_ARGUMENT), - Arguments.of(ACTION_USAGE_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, REDEFINITION_ARGUMENT), + Arguments.of(ACTION_DEFINITION_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, FEATURE_TYPING_ARGUMENT.withExtraBorderNodes(1)), + Arguments.of(ACTION_DEFINITION_ARGUMENT, nestedItemWithBorderNode, ACTION_DEFINITION_ARGUMENT, SUBCLASSIFICATION_ARGUMENT.withExtraBorderNodes(1)), + Arguments.of(ACTION_USAGE_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, SUBSETTING_ARGUMENT.withExtraBorderNodes(1)), + Arguments.of(ACTION_USAGE_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, REFERENCE_SUBSETTING_ARGUMENT.withExtraBorderNodes(1)), + Arguments.of(ACTION_USAGE_ARGUMENT, nestedItemWithBorderNode, ACTION_USAGE_ARGUMENT, REDEFINITION_ARGUMENT.withExtraBorderNodes(1)), Arguments.of(PORT_USAGE_ARGUMENT, nestedItemWithBorderNode, PORT_USAGE_ARGUMENT, SUBSETTING_ARGUMENT), Arguments.of(PORT_USAGE_ARGUMENT, nestedItemWithBorderNode, PORT_USAGE_ARGUMENT, REFERENCE_SUBSETTING_ARGUMENT), Arguments.of(PORT_DEFINITION_ARGUMENT, nestedItemWithBorderNode, PORT_DEFINITION_ARGUMENT, SUBCLASSIFICATION_ARGUMENT) diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractItemUsageBorderNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractItemUsageBorderNodeDescriptionProvider.java new file mode 100644 index 0000000000..08e224f74f --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractItemUsageBorderNodeDescriptionProvider.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.syson.diagram.common.view.nodes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.eclipse.emf.ecore.EReference; +import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.diagram.ConditionalNodeStyle; +import org.eclipse.sirius.components.view.diagram.DiagramDescription; +import org.eclipse.sirius.components.view.diagram.EdgeTool; +import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.sirius.components.view.diagram.NodePalette; +import org.eclipse.sirius.components.view.diagram.NodeStyleDescription; +import org.eclipse.sirius.components.view.diagram.OutsideLabelDescription; +import org.eclipse.sirius.components.view.diagram.OutsideLabelStyle; +import org.eclipse.sirius.components.view.diagram.SynchronizationPolicy; +import org.eclipse.sirius.components.view.diagram.UserResizableDirection; +import org.eclipse.syson.diagram.common.view.services.ViewEdgeToolService; +import org.eclipse.syson.services.UtilService; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ServiceMethod; +import org.eclipse.syson.util.SysMLMetamodelHelper; +import org.eclipse.syson.util.ViewConstants; + +/** + * Common behavior for all item usage border node description. + * + * @author gcoutabe + */ +public abstract class AbstractItemUsageBorderNodeDescriptionProvider extends AbstractNodeDescriptionProvider { + + protected final IDescriptionNameGenerator descriptionNameGenerator; + + protected final EReference eReference; + + public AbstractItemUsageBorderNodeDescriptionProvider(EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(colorProvider); + this.eReference = Objects.requireNonNull(eReference); + this.descriptionNameGenerator = Objects.requireNonNull(descriptionNameGenerator); + } + + protected abstract String getSemanticCandidatesExpression(); + + protected abstract String getName(); + + protected abstract OutsideLabelDescription createOutsideLabelDescription(); + + protected abstract List getEdgeTools(IViewDiagramElementFinder cache, NodeDescription nodeDescription); + + protected abstract NodePalette createNodePalette(IViewDiagramElementFinder cache, NodeDescription nodeDescription); + + @Override + public NodeDescription create() { + String domainType = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getItemUsage()); + return this.diagramBuilderHelper.newNodeDescription() + .defaultHeightExpression("10") + .defaultWidthExpression("10") + .domainType(domainType) + .outsideLabels(this.createOutsideLabelDescription()) + .name(this.getName()) + .semanticCandidatesExpression(this.getSemanticCandidatesExpression()) + .style(this.createItemUnsetNodeStyle()) + .conditionalStyles(this.createItemUsageConditionalNodeStyles().toArray(ConditionalNodeStyle[]::new)) + .userResizable(UserResizableDirection.NONE) + .synchronizationPolicy(SynchronizationPolicy.SYNCHRONIZED) + .build(); + } + + protected IDescriptionNameGenerator getDescriptionNameGenerator() { + return this.descriptionNameGenerator; + } + + private NodeStyleDescription createItemUnsetNodeStyle() { + return this.diagramBuilderHelper.newRectangularNodeStyleDescription() + .borderColor(this.colorProvider.getColor(ViewConstants.DEFAULT_BORDER_COLOR)) + .borderRadius(0) + .background(this.colorProvider.getColor(ViewConstants.DEFAULT_BACKGROUND_COLOR)) + .build(); + } + + protected OutsideLabelStyle createOutsideLabelStyle() { + return this.diagramBuilderHelper.newOutsideLabelStyle() + .bold(false) + .borderSize(0) + .fontSize(12) + .italic(false) + .labelColor(this.colorProvider.getColor(ViewConstants.DEFAULT_LABEL_COLOR)) + .showIconExpression(AQLConstants.AQL_FALSE) + .strikeThrough(false) + .underline(false) + .build(); + } + + private List createItemUsageConditionalNodeStyles() { + var borderColor = this.colorProvider.getColor(ViewConstants.DEFAULT_BORDER_COLOR); + return List.of( + this.diagramBuilderHelper.newConditionalNodeStyle() + .condition(ServiceMethod.of0(UtilService::isInFeature).aqlSelf()) + .style(this.createImageNodeStyleDescription("/images/feature_in.svg", borderColor, true)) + .build(), + this.diagramBuilderHelper.newConditionalNodeStyle() + .condition(ServiceMethod.of0(UtilService::isOutFeature).aqlSelf()) + .style(this.createImageNodeStyleDescription("/images/feature_out.svg", borderColor, true)) + .build(), + this.diagramBuilderHelper.newConditionalNodeStyle() + .condition(ServiceMethod.of0(UtilService::isInOutFeature).aqlSelf()) + .style(this.createImageNodeStyleDescription("/images/feature_inout.svg", borderColor, true)) + .build()); + } + + @Override + public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { + var optItemUsageBorderNodeDescription = cache.getNodeDescription(this.getName()); + + NodeDescription nodeDescription = optItemUsageBorderNodeDescription.get(); + nodeDescription.setPalette(this.createNodePalette(cache, nodeDescription)); + } + + private List getBindingConnectorAsUsageToolTarget(IViewDiagramElementFinder cache) { + var nodeDescriptions = new ArrayList(); + cache.getNodeDescription(this.getName()).ifPresent(nodeDescriptions::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), this.eReference)).ifPresent(nodeDescriptions::add); + return nodeDescriptions; + } + + protected EdgeTool createBindingConnectorAsUsageEdgeTool(IViewDiagramElementFinder cache) { + return this.getViewEdgeToolService(cache).createBindingConnectorAsUsageEdgeTool(this.getBindingConnectorAsUsageToolTarget(cache)); + } + + protected EdgeTool createFlowUsageEdgeTool(IViewDiagramElementFinder cache) { + return this.getViewEdgeToolService(cache).createFlowUsageEdgeTool(this.getFlowUsageToolTargetDescriptions(cache, this.descriptionNameGenerator)); + } + + protected ViewEdgeToolService getViewEdgeToolService(IViewDiagramElementFinder cache) { + return new ViewEdgeToolService(this.viewBuilderHelper, this.diagramBuilderHelper, cache.getNodeDescriptions(), this.descriptionNameGenerator); + } + +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractNodeDescriptionProvider.java index 13742cecd5..ee889cc2ec 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractNodeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractNodeDescriptionProvider.java @@ -94,6 +94,8 @@ protected List getFlowUsageToolTargetDescriptions(IViewDiagramE cache.getNodeDescription(descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort())).ifPresent(nodes::add); cache.getNodeDescription(descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); cache.getNodeDescription(descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); + cache.getNodeDescription(descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); + cache.getNodeDescription(descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); cache.getNodeDescription(descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(nodes::add); cache.getNodeDescription(descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(nodes::add); return nodes; diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedItemUsageBorderNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedItemUsageBorderNodeDescriptionProvider.java new file mode 100644 index 0000000000..077495c98d --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/InheritedItemUsageBorderNodeDescriptionProvider.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.syson.diagram.common.view.nodes; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.EReference; +import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +import org.eclipse.sirius.components.view.diagram.EdgeTool; +import org.eclipse.sirius.components.view.diagram.NodeDescription; +import org.eclipse.sirius.components.view.diagram.NodePalette; +import org.eclipse.sirius.components.view.diagram.OutsideLabelDescription; +import org.eclipse.sirius.components.view.diagram.OutsideLabelPosition; +import org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.AQLConstants; +import org.eclipse.syson.util.AQLUtils; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ServiceMethod; + +/** + * Used to create the inherited item usage border node description. + * + * @author gcoutable + */ +public class InheritedItemUsageBorderNodeDescriptionProvider extends AbstractItemUsageBorderNodeDescriptionProvider { + + public InheritedItemUsageBorderNodeDescriptionProvider(EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(eReference, colorProvider, descriptionNameGenerator); + } + + @Override + protected String getSemanticCandidatesExpression() { + return ServiceMethod.of1(DiagramQueryAQLService::getInheritedCompartmentItems).aqlSelf(AQLUtils.aqlString(this.eReference.getName())); + } + + @Override + protected String getName() { + return this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), this.eReference); + } + + @Override + protected OutsideLabelDescription createOutsideLabelDescription() { + return this.diagramBuilderHelper.newOutsideLabelDescription() + .labelExpression(AQLConstants.AQL + "'^' + self.getBorderNodeUsageLabel()") + .position(OutsideLabelPosition.BOTTOM_CENTER) + .style(this.createOutsideLabelStyle()) + .build(); + } + + @Override + protected List getEdgeTools(IViewDiagramElementFinder cache, NodeDescription nodeDescription) { + List edgeTools = new ArrayList<>(); + edgeTools.add(this.createBindingConnectorAsUsageEdgeTool(cache)); + edgeTools.add(this.createFlowUsageEdgeTool(cache)); + return edgeTools; + } + + @Override + protected NodePalette createNodePalette(IViewDiagramElementFinder cache, NodeDescription nodeDescription) { + return this.diagramBuilderHelper.newNodePalette() + .toolSections(this.defaultToolsFactory.createDefaultHideRevealNodeToolSection()) + .edgeTools(this.getEdgeTools(cache, nodeDescription).toArray(EdgeTool[]::new)) + .build(); + } +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/ItemUsageBorderNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/ItemUsageBorderNodeDescriptionProvider.java index f16f84f1fd..87caf524f7 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/ItemUsageBorderNodeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/ItemUsageBorderNodeDescriptionProvider.java @@ -14,96 +14,47 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import org.eclipse.emf.ecore.EReference; import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; import org.eclipse.sirius.components.view.builder.providers.IColorProvider; -import org.eclipse.sirius.components.view.diagram.ConditionalNodeStyle; -import org.eclipse.sirius.components.view.diagram.DiagramDescription; import org.eclipse.sirius.components.view.diagram.EdgeTool; import org.eclipse.sirius.components.view.diagram.NodeDescription; import org.eclipse.sirius.components.view.diagram.NodePalette; -import org.eclipse.sirius.components.view.diagram.NodeStyleDescription; import org.eclipse.sirius.components.view.diagram.OutsideLabelDescription; import org.eclipse.sirius.components.view.diagram.OutsideLabelPosition; -import org.eclipse.sirius.components.view.diagram.OutsideLabelStyle; -import org.eclipse.sirius.components.view.diagram.SynchronizationPolicy; -import org.eclipse.sirius.components.view.diagram.UserResizableDirection; -import org.eclipse.syson.diagram.common.view.services.ViewEdgeToolService; import org.eclipse.syson.diagram.services.aql.DiagramMutationAQLService; import org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService; import org.eclipse.syson.services.DeleteService; -import org.eclipse.syson.services.UtilService; import org.eclipse.syson.sysml.SysmlPackage; import org.eclipse.syson.util.AQLConstants; import org.eclipse.syson.util.IDescriptionNameGenerator; import org.eclipse.syson.util.ServiceMethod; import org.eclipse.syson.util.SysMLMetamodelHelper; -import org.eclipse.syson.util.ViewConstants; /** * Used to create the item usage border node description. * * @author arthur daussy */ -public class ItemUsageBorderNodeDescriptionProvider extends AbstractNodeDescriptionProvider { - - private final IDescriptionNameGenerator descriptionNameGenerator; - - private final EReference eReference; +public class ItemUsageBorderNodeDescriptionProvider extends AbstractItemUsageBorderNodeDescriptionProvider { public ItemUsageBorderNodeDescriptionProvider(EReference eReference, IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { - super(colorProvider); - this.eReference = Objects.requireNonNull(eReference); - this.descriptionNameGenerator = Objects.requireNonNull(descriptionNameGenerator); - } - - private List getBindingConnectorAsUsageToolTarget(IViewDiagramElementFinder cache) { - var nodeDescriptions = new ArrayList(); - cache.getNodeDescription(this.getName()).ifPresent(nodeDescriptions::add); - cache.getNodeDescription(this.getDescriptionNameGenerator().getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), this.eReference)).ifPresent(nodeDescriptions::add); - return nodeDescriptions; + super(eReference, colorProvider, descriptionNameGenerator); } - private String getSemanticCandidatesExpression() { + @Override + protected String getSemanticCandidatesExpression() { var itemUsage = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getItemUsage()); return AQLConstants.AQL_SELF + "." + this.eReference.getName() + "->select(e | e.oclIsTypeOf(" + itemUsage + "))"; } - private String getName() { + @Override + protected String getName() { return this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), this.eReference); } @Override - public NodeDescription create() { - String domainType = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getItemUsage()); - return this.diagramBuilderHelper.newNodeDescription() - .defaultHeightExpression("10") - .defaultWidthExpression("10") - .domainType(domainType) - .outsideLabels(this.createOutsideLabelDescription()) - .name(this.getName()) - .semanticCandidatesExpression(this.getSemanticCandidatesExpression()) - .style(this.createItemUnsetNodeStyle()) - .conditionalStyles(this.createItemUsageConditionalNodeStyles().toArray(ConditionalNodeStyle[]::new)) - .userResizable(UserResizableDirection.NONE) - .synchronizationPolicy(SynchronizationPolicy.SYNCHRONIZED) - .build(); - } - - protected IDescriptionNameGenerator getDescriptionNameGenerator() { - return this.descriptionNameGenerator; - } - - private NodeStyleDescription createItemUnsetNodeStyle() { - return this.diagramBuilderHelper.newRectangularNodeStyleDescription() - .borderColor(this.colorProvider.getColor(ViewConstants.DEFAULT_BORDER_COLOR)) - .borderRadius(0) - .background(this.colorProvider.getColor(ViewConstants.DEFAULT_BACKGROUND_COLOR)) - .build(); - } - protected OutsideLabelDescription createOutsideLabelDescription() { return this.diagramBuilderHelper.newOutsideLabelDescription() .labelExpression(ServiceMethod.of0(DiagramQueryAQLService::getBorderNodeUsageLabel).aqlSelf()) @@ -112,45 +63,16 @@ protected OutsideLabelDescription createOutsideLabelDescription() { .build(); } - private OutsideLabelStyle createOutsideLabelStyle() { - return this.diagramBuilderHelper.newOutsideLabelStyle() - .bold(false) - .borderSize(0) - .fontSize(12) - .italic(false) - .labelColor(this.colorProvider.getColor(ViewConstants.DEFAULT_LABEL_COLOR)) - .showIconExpression(AQLConstants.AQL_FALSE) - .strikeThrough(false) - .underline(false) - .build(); - } - - private List createItemUsageConditionalNodeStyles() { - var borderColor = this.colorProvider.getColor(ViewConstants.DEFAULT_BORDER_COLOR); - return List.of( - this.diagramBuilderHelper.newConditionalNodeStyle() - .condition(ServiceMethod.of0(UtilService::isInFeature).aqlSelf()) - .style(this.createImageNodeStyleDescription("/images/feature_in.svg", borderColor, true)) - .build(), - this.diagramBuilderHelper.newConditionalNodeStyle() - .condition(ServiceMethod.of0(UtilService::isOutFeature).aqlSelf()) - .style(this.createImageNodeStyleDescription("/images/feature_out.svg", borderColor, true)) - .build(), - this.diagramBuilderHelper.newConditionalNodeStyle() - .condition(ServiceMethod.of0(UtilService::isInOutFeature).aqlSelf()) - .style(this.createImageNodeStyleDescription("/images/feature_inout.svg", borderColor, true)) - .build()); - } - @Override - public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { - var optItemUsageBorderNodeDescription = cache.getNodeDescription(this.getName()); - - NodeDescription nodeDescription = optItemUsageBorderNodeDescription.get(); - nodeDescription.setPalette(this.createNodePalette(cache, nodeDescription)); + protected List getEdgeTools(IViewDiagramElementFinder cache, NodeDescription nodeDescription) { + List edgeTools = new ArrayList<>(); + edgeTools.add(this.createBindingConnectorAsUsageEdgeTool(cache)); + edgeTools.add(this.createFlowUsageEdgeTool(cache)); + return edgeTools; } - private NodePalette createNodePalette(IViewDiagramElementFinder cache, NodeDescription nodeDescription) { + @Override + protected NodePalette createNodePalette(IViewDiagramElementFinder cache, NodeDescription nodeDescription) { var changeContext = this.viewBuilderHelper.newChangeContext() .expression(ServiceMethod.of0(DeleteService::deleteFromModel).aqlSelf()); @@ -170,23 +92,8 @@ private NodePalette createNodePalette(IViewDiagramElementFinder cache, NodeDescr .deleteTool(deleteTool.build()) .labelEditTool(editTool.build()) .toolSections(this.defaultToolsFactory.createDefaultHideRevealNodeToolSection()) - .edgeTools( - this.createBindingConnectorAsUsageEdgeTool(cache), - this.createFlowUsageEdgeTool(cache)) + .edgeTools(this.getEdgeTools(cache, nodeDescription).toArray(EdgeTool[]::new)) .quickAccessTools(this.getDuplicateElementAndNodeTool()) .build(); } - - private EdgeTool createBindingConnectorAsUsageEdgeTool(IViewDiagramElementFinder cache) { - return this.getViewEdgeToolService(cache).createBindingConnectorAsUsageEdgeTool(this.getBindingConnectorAsUsageToolTarget(cache)); - } - - protected EdgeTool createFlowUsageEdgeTool(IViewDiagramElementFinder cache) { - return this.getViewEdgeToolService(cache).createFlowUsageEdgeTool(this.getFlowUsageToolTargetDescriptions(cache, this.descriptionNameGenerator)); - } - - protected ViewEdgeToolService getViewEdgeToolService(IViewDiagramElementFinder cache) { - return new ViewEdgeToolService(this.viewBuilderHelper, this.diagramBuilderHelper, cache.getNodeDescriptions(), this.descriptionNameGenerator); - } - } 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 dd8bcad3db..3a5568bafd 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 @@ -59,6 +59,7 @@ import org.eclipse.syson.diagram.common.view.nodes.FramedConcernCompartmentNodeDescription; import org.eclipse.syson.diagram.common.view.nodes.ImportedPackageNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.InheritedCompartmentItemNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.InheritedItemUsageBorderNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.InterconnectionCompartmentNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ItemUsageBorderNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.JoinActionNodeDescriptionProvider; @@ -495,6 +496,8 @@ private List> createDiagramElementDescript .add(new InheritedPortUsageBorderNodeDescriptionProvider(SysmlPackage.eINSTANCE.getDefinition_OwnedPort(), colorProvider, this.getDescriptionNameGenerator())); diagramElementDescriptionProviders.add(new ItemUsageBorderNodeDescriptionProvider(SysmlPackage.eINSTANCE.getDefinition_OwnedItem(), colorProvider, this.getDescriptionNameGenerator())); diagramElementDescriptionProviders.add(new ItemUsageBorderNodeDescriptionProvider(SysmlPackage.eINSTANCE.getUsage_NestedItem(), colorProvider, this.getDescriptionNameGenerator())); + diagramElementDescriptionProviders.add(new InheritedItemUsageBorderNodeDescriptionProvider(SysmlPackage.eINSTANCE.getDefinition_OwnedItem(), colorProvider, this.getDescriptionNameGenerator())); + diagramElementDescriptionProviders.add(new InheritedItemUsageBorderNodeDescriptionProvider(SysmlPackage.eINSTANCE.getUsage_NestedItem(), colorProvider, this.getDescriptionNameGenerator())); diagramElementDescriptionProviders.add(new ReferenceUsageBorderNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); diagramElementDescriptionProviders.add(new InheritedReferenceUsageBorderNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/BindingConnectorAsUsageEdgeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/BindingConnectorAsUsageEdgeDescriptionProvider.java index fbe9e74fbc..3edc908f31 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/BindingConnectorAsUsageEdgeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/BindingConnectorAsUsageEdgeDescriptionProvider.java @@ -54,6 +54,8 @@ protected List getSourceNodes(IViewDiagramElementFinder cache) cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPort())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort())) .ifPresent(nodes::add); diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FeatureValueEdgeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FeatureValueEdgeDescriptionProvider.java index 542147f689..d4927d6e87 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FeatureValueEdgeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FeatureValueEdgeDescriptionProvider.java @@ -52,6 +52,8 @@ protected List getSourceNodes(IViewDiagramElementFinder cache) List nodes = new ArrayList<>(); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPort())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedPort())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getPortUsage(), SysmlPackage.eINSTANCE.getUsage_NestedPort())).ifPresent(nodes::add); diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FlowUsageEdgeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FlowUsageEdgeDescriptionProvider.java index 1088ab6f64..3fb7e3e5e0 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FlowUsageEdgeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/edges/FlowUsageEdgeDescriptionProvider.java @@ -57,6 +57,8 @@ protected List getSourceNodes(IViewDiagramElementFinder cache) .ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(nodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(nodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(nodes::add); return nodes; diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/DefinitionNodeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/DefinitionNodeDescriptionProvider.java index b31dffc7d6..799af72e2c 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/DefinitionNodeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/DefinitionNodeDescriptionProvider.java @@ -79,6 +79,7 @@ protected Set getReusedBorderNodes(IViewDiagramElementFinder ca }); if (SysmlPackage.eINSTANCE.getActionDefinition().equals(this.eClass)) { cache.getNodeDescription(this.getDescriptionNameGenerator().getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(borderNodes::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())).ifPresent(borderNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(borderNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(borderNodes::add); } else if (SysmlPackage.eINSTANCE.getPortDefinition().equals(this.eClass)) { diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java index a13ab9689e..a83916e686 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/FakeNodeDescriptionProvider.java @@ -225,5 +225,9 @@ private void addReusableBorderedNode(IViewDiagramElementFinder cache, IDescripti .ifPresent(childrenNodes::add); cache.getNodeDescription(this.descriptionNameGenerator.getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())) .ifPresent(childrenNodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getDefinition_OwnedItem())) + .ifPresent(childrenNodes::add); + cache.getNodeDescription(this.descriptionNameGenerator.getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())) + .ifPresent(childrenNodes::add); } } diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/UsageNodeDescriptionProvider.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/UsageNodeDescriptionProvider.java index 245482bd81..edafcb388e 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/UsageNodeDescriptionProvider.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/nodes/UsageNodeDescriptionProvider.java @@ -116,6 +116,7 @@ protected Set getReusedBorderNodes(IViewDiagramElementFinder ca }); if (SysmlPackage.eINSTANCE.getActionUsage().equals(this.eClass)) { cache.getNodeDescription(this.getDescriptionNameGenerator().getBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(borderNodes::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getItemUsage(), SysmlPackage.eINSTANCE.getUsage_NestedItem())).ifPresent(borderNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(borderNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getInheritedBorderNodeName(SysmlPackage.eINSTANCE.getReferenceUsage())).ifPresent(borderNodes::add); } else if (SysmlPackage.eINSTANCE.getPortUsage().equals(this.eClass)) { diff --git a/doc/content/modules/user-manual/assets/images/release-notes-action-inherited-item-border-nodes.png b/doc/content/modules/user-manual/assets/images/release-notes-action-inherited-item-border-nodes.png new file mode 100644 index 0000000000000000000000000000000000000000..b152327db28d0d2cb99efdf72fb58a17cab3d02d GIT binary patch literal 22637 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