From 7927bdb6ca1e42565888ee2c1ab8fbd249c03ecc Mon Sep 17 00:00:00 2001 From: Jerome Gout Date: Fri, 24 Apr 2026 09:01:59 +0200 Subject: [PATCH] [2112][WIP] Handle Start and Done StateUsages Bug: https://github.com/eclipse-syson/syson/issues/2112 Signed-off-by: Jerome Gout --- .../eclipse/syson/services/UtilService.java | 44 ++++++- ...ractTransitionEdgeDescriptionProvider.java | 10 +- .../AbstractFakeNodeDescriptionProvider.java | 4 + .../DoneStateNodeDescriptionProvider.java | 77 +++++++++++++ .../StartStateNodeDescriptionProvider.java | 109 ++++++++++++++++++ ...ionCompartmentNodeDescriptionProvider.java | 6 + .../view/services/ViewCreateService.java | 22 ++++ .../view/services/ViewEdgeToolSwitch.java | 4 + .../view/tools/DoneStateNodeToolProvider.java | 52 +++++++++ .../tools/StartStateNodeToolProvider.java | 52 +++++++++ .../view/SDVDiagramDescriptionProvider.java | 4 + .../DefinitionNodeDescriptionProvider.java | 4 + .../nodes/UsageNodeDescriptionProvider.java | 4 + .../services/SDVNodeToolSectionSwitch.java | 6 + 14 files changed, 394 insertions(+), 4 deletions(-) create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/DoneStateNodeDescriptionProvider.java create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StartStateNodeDescriptionProvider.java create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/DoneStateNodeToolProvider.java create mode 100644 backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/StartStateNodeToolProvider.java 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 ce289d355..e851d17d2 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 @@ -238,7 +238,7 @@ public List getAllNonExhibitStates(Element element) { * * @param eObject * the {@link EObject} stored in a {@link ResourceSet} - * @param type + * @param eClass * the searched type, represented by its qualified name * @return a list of reachable object */ @@ -246,6 +246,20 @@ public List getAllReachable(EObject eObject, EClass eClass) { return this.getAllReachableType(eObject, eClass); } + /** + * * Get all reachable elements of the type given by the {@link EClass} in the {@link ResourceSet} of the given type + * (represented by its qualified name) without considering elements inside standard libs. + * + * @param eObject + * the {@link EObject} stored in a {@link ResourceSet} + * @param eClass + * the searched type, represented by its qualified name + * @return a list of reachable object + */ + public List getAllReachableWithoutStandardLibs(EObject eObject, EClass eClass) { + return this.getAllReachableType(eObject, eClass, false); + } + /** * Get all reachable elements of the type given by the {@link EClass} in the {@link ResourceSet} of the given * {@link EObject}. @@ -605,6 +619,18 @@ public ActionUsage retrieveStandardStartAction(Element eObject) { return this.findByNameAndTypeInStandardLibraries(eObject, ActionUsage.class, "Actions::Action::start"); } + /** + * Retrieve the start state defined inside the standard library States. + * + * @param eObject + * an object to access to the library resources. + * + * @return the standard start StateUsage defined in the States library. + */ + public StateUsage retrieveStandardStartState(Element eObject) { + return this.findByNameAndTypeInStandardLibraries(eObject, StateUsage.class, "States::StateAction::start"); + } + /** * Retrieve the done action defined inside the standard library Actions. * @@ -617,6 +643,18 @@ public ActionUsage retrieveStandardDoneAction(Element eObject) { return this.findByNameAndTypeInStandardLibraries(eObject, ActionUsage.class, "Actions::Action::done"); } + /** + * Retrieve the done state defined inside the standard library States. + * + * @param eObject + * an object to access to the library resources. + * + * @return the standard done StateUsage defined in the States library. + */ + public ActionUsage retrieveStandardDoneState(Element eObject) { + return this.findByNameAndTypeInStandardLibraries(eObject, ActionUsage.class, "States::StateAction::done"); + } + private T findByNameAndTypeInStandardLibraries(Element context, Class klass, String qualifiedName) { return context.eResource().getResourceSet().getResources().stream() .flatMap(resource -> this.getLibraries(resource, true).stream()) @@ -1022,6 +1060,10 @@ public boolean isUnsynchronized(Element element) { isUnsynchronized = true; } else if (Objects.equals(element, this.retrieveStandardDoneAction(element))) { isUnsynchronized = true; + } else if (Objects.equals(element, this.retrieveStandardStartState(element))) { + isUnsynchronized = true; + } else if (Objects.equals(element, this.retrieveStandardDoneState(element))) { + isUnsynchronized = true; } else if (element instanceof NamespaceImport) { isUnsynchronized = true; } else if (element instanceof AnnotatingElement) { diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractTransitionEdgeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractTransitionEdgeDescriptionProvider.java index d4b8ad14c..5f7b79301 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractTransitionEdgeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/edges/AbstractTransitionEdgeDescriptionProvider.java @@ -33,7 +33,9 @@ import org.eclipse.sirius.components.view.diagram.NodeTool; import org.eclipse.sirius.components.view.diagram.SynchronizationPolicy; import org.eclipse.syson.diagram.common.view.nodes.DoneActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StartActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.StartStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.services.ViewEdgeService; import org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService; import org.eclipse.syson.services.UtilService; @@ -73,7 +75,7 @@ public EdgeDescription create() { .name(this.getEdgeDescriptionName()) .preconditionExpression(ServiceMethod.of2(ViewEdgeService::isInSameGraphicalContainer).aql(org.eclipse.sirius.components.diagrams.description.EdgeDescription.GRAPHICAL_EDGE_SOURCE, org.eclipse.sirius.components.diagrams.description.EdgeDescription.GRAPHICAL_EDGE_TARGET, org.eclipse.sirius.components.diagrams.description.DiagramDescription.CACHE)) - .semanticCandidatesExpression(ServiceMethod.of1(UtilService::getAllReachable).aqlSelf(domainType)) + .semanticCandidatesExpression(ServiceMethod.of1(UtilService::getAllReachableWithoutStandardLibs).aqlSelf(domainType)) .sourceExpression(AQLConstants.AQL_SELF + "." + SysmlPackage.eINSTANCE.getTransitionUsage_Source().getName()) .style(this.createDefaultEdgeStyle()) .conditionalStyles(this.createStateConditionalStyle()) @@ -181,11 +183,13 @@ protected List getAllActionOrStateUsage(IViewDiagramElementFind } protected boolean isStartNode(NodeDescription n) { - return Objects.equals(this.getDescriptionNameGenerator().getNodeName(StartActionNodeDescriptionProvider.START_ACTION_NAME), n.getName()); + return Objects.equals(this.getDescriptionNameGenerator().getNodeName(StartActionNodeDescriptionProvider.START_ACTION_NAME), n.getName()) || + Objects.equals(this.getDescriptionNameGenerator().getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME), n.getName()); } protected boolean isDoneNode(NodeDescription n) { - return Objects.equals(this.getDescriptionNameGenerator().getNodeName(DoneActionNodeDescriptionProvider.DONE_ACTION_NAME), n.getName()); + return Objects.equals(this.getDescriptionNameGenerator().getNodeName(DoneActionNodeDescriptionProvider.DONE_ACTION_NAME), n.getName()) || + Objects.equals(this.getDescriptionNameGenerator().getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME), n.getName()); } protected boolean isActionOrStateUsage(NodeDescription nodeDescription) { diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractFakeNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractFakeNodeDescriptionProvider.java index aa45b3078..268702177 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractFakeNodeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/AbstractFakeNodeDescriptionProvider.java @@ -124,5 +124,9 @@ protected void addReusableCustomNodes(IViewDiagramElementFinder cache, List { + nodeDescription.setPalette(this.createNodePalette()); + }); + } + + private NodePalette createNodePalette() { + return this.diagramBuilderHelper.newNodePalette() + .quickAccessTools(this.getDeleteFromDiagramTool()) + .toolSections(this.defaultToolsFactory.createDefaultHideRevealNodeToolSection()) + .build(); + } +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StartStateNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StartStateNodeDescriptionProvider.java new file mode 100644 index 000000000..9f26ccfbb --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StartStateNodeDescriptionProvider.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2024, 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.sirius.components.collaborative.diagrams.api.IDiagramService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.diagrams.description.EdgeDescription; +import org.eclipse.sirius.components.view.builder.IViewDiagramElementFinder; +import org.eclipse.sirius.components.view.builder.providers.IColorProvider; +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.SynchronizationPolicy; +import org.eclipse.sirius.components.view.diagram.UserResizableDirection; +import org.eclipse.syson.diagram.common.view.services.ViewCreateService; +import org.eclipse.syson.services.UtilService; +import org.eclipse.syson.sysml.SysmlPackage; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ServiceMethod; +import org.eclipse.syson.util.SysMLMetamodelHelper; + +/** + * Used to create the starting node description of a state. + * + * @author Jerome Gout + */ +public class StartStateNodeDescriptionProvider extends AbstractNodeDescriptionProvider { + + public static final String START_STATE_NAME = "StartState"; + + private final IDescriptionNameGenerator descriptionNameGenerator; + + public StartStateNodeDescriptionProvider(IColorProvider colorProvider, IDescriptionNameGenerator descriptionNameGenerator) { + super(colorProvider); + this.descriptionNameGenerator = Objects.requireNonNull(descriptionNameGenerator); + } + + @Override + public NodeDescription create() { + String domainType = SysMLMetamodelHelper.buildQualifiedName(SysmlPackage.eINSTANCE.getStateUsage()); + return this.diagramBuilderHelper.newNodeDescription() + .collapsible(false) + .domainType(domainType) + .defaultWidthExpression("28") + .defaultHeightExpression("28") + .name(this.descriptionNameGenerator.getNodeName(START_STATE_NAME)) + .semanticCandidatesExpression(ServiceMethod.of0(UtilService::retrieveStandardStartState).aqlSelf()) + .style(this.createImageNodeStyleDescription("images/start_action.svg")) + .userResizable(UserResizableDirection.NONE) + .synchronizationPolicy(SynchronizationPolicy.UNSYNCHRONIZED) + .build(); + } + + @Override + public void link(DiagramDescription diagramDescription, IViewDiagramElementFinder cache) { + // this nodeDescription has not been added to the diagramDescription children but to the fakeNodeDescription + // children instead + cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(START_STATE_NAME)).ifPresent(nodeDescription -> { + nodeDescription.setPalette(this.createNodePalette(cache)); + }); + } + + private NodePalette createNodePalette(IViewDiagramElementFinder cache) { + var edgeTools = new ArrayList(this.getEdgeTools(cache)); + + return this.diagramBuilderHelper.newNodePalette() + .edgeTools(edgeTools.toArray(EdgeTool[]::new)) + .quickAccessTools(this.getDeleteFromDiagramTool()) + .toolSections(this.defaultToolsFactory.createDefaultHideRevealNodeToolSection()) + .build(); + } + + private List getEdgeTools(IViewDiagramElementFinder cache) { + var targetElementDescriptions = this.getStartTargetDescriptions(cache); + + var createStartEdgeTool = this.diagramBuilderHelper.newEdgeTool().name(this.descriptionNameGenerator.getCreationToolName(SysmlPackage.eINSTANCE.getTransitionUsage())) + .iconURLsExpression("/icons/full/obj16/TransitionUsage.svg") + .body(this.viewBuilderHelper.newChangeContext() + .expression( + ServiceMethod.of5(ViewCreateService::createTransitionUsage).aql(EdgeDescription.SEMANTIC_EDGE_SOURCE, EdgeDescription.SEMANTIC_EDGE_TARGET, EdgeDescription.EDGE_SOURCE, + EdgeDescription.EDGE_TARGET, IEditingContext.EDITING_CONTEXT, IDiagramService.DIAGRAM_SERVICES)) + .build()) + .targetElementDescriptions(targetElementDescriptions.toArray(NodeDescription[]::new)) + .build(); + + return List.of(createStartEdgeTool); + } + + private List getStartTargetDescriptions(IViewDiagramElementFinder cache) { + var targets = new ArrayList(); + cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(SysmlPackage.eINSTANCE.getStateUsage())).ifPresent(targets::add); + return targets; + } +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StateTransitionCompartmentNodeDescriptionProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StateTransitionCompartmentNodeDescriptionProvider.java index 48d647a19..fba5b81cc 100644 --- a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StateTransitionCompartmentNodeDescriptionProvider.java +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/nodes/StateTransitionCompartmentNodeDescriptionProvider.java @@ -32,6 +32,8 @@ import org.eclipse.sirius.components.view.diagram.SynchronizationPolicy; import org.eclipse.sirius.components.view.diagram.UserResizableDirection; import org.eclipse.syson.diagram.common.view.services.description.ToolConstants; +import org.eclipse.syson.diagram.common.view.tools.DoneStateNodeToolProvider; +import org.eclipse.syson.diagram.common.view.tools.StartStateNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.StateTransitionCompartmentNodeToolProvider; import org.eclipse.syson.sysml.SysmlPackage; import org.eclipse.syson.util.AQLConstants; @@ -76,6 +78,8 @@ public void link(DiagramDescription diagramDescription, IViewDiagramElementFinde cache.getNodeDescription(this.name).ifPresent(nodeDescription -> { cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(SysmlPackage.eINSTANCE.getStateUsage())).ifPresent(nodeDescription.getReusedChildNodeDescriptions()::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(SysmlPackage.eINSTANCE.getStateDefinition())).ifPresent(nodeDescription.getReusedChildNodeDescriptions()::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME)).ifPresent(nodeDescription.getReusedChildNodeDescriptions()::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME)).ifPresent(nodeDescription.getReusedChildNodeDescriptions()::add); nodeDescription.setPalette(this.createCompartmentPalette(cache)); }); } @@ -117,6 +121,8 @@ protected NodePalette createCompartmentPalette(IViewDiagramElementFinder cache) var toolSections = this.toolDescriptionService.createDefaultNodeToolSections(); // Do not use getItemCreationToolProvider because the compartment contains multiple creation tools. + this.toolDescriptionService.addNodeTool(toolSections, ToolConstants.BEHAVIOR, new StartStateNodeToolProvider(this.eClass, this.getDescriptionNameGenerator()).create(cache)); + this.toolDescriptionService.addNodeTool(toolSections, ToolConstants.BEHAVIOR, new DoneStateNodeToolProvider(this.eClass, this.getDescriptionNameGenerator()).create(cache)); this.toolDescriptionService.addNodeTool(toolSections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(false, false).create(cache)); this.toolDescriptionService.addNodeTool(toolSections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(true, false).create(cache)); this.toolDescriptionService.addNodeTool(toolSections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(false, true).create(cache)); 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 6ba03ad18..078a8a749 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 @@ -784,6 +784,17 @@ public ActionUsage addStartAction(Element ownerElement) { return this.utilService.retrieveStandardStartAction(ownerElement); } + /** + * Add the standard start state as the child of the given element. + * + * @param ownerElement + * an element that will own the standard start state. + * @return the {@link Membership} element containing the start state in its memberElement feature. + */ + public ActionUsage addStartState(Element ownerElement) { + return this.utilService.retrieveStandardStartState(ownerElement); + } + /** * Add the standard done action as the child of the given element. * @@ -795,6 +806,17 @@ public ActionUsage addDoneAction(Element ownerElement) { return this.utilService.retrieveStandardDoneAction(ownerElement); } + /** + * Add the standard done state as the child of the given element. + * + * @param ownerElement + * an element that will own the standard done state. + * @return the {@link Membership} element containing the done state in its memberElement feature. + */ + public ActionUsage addDoneState(Element ownerElement) { + return this.utilService.retrieveStandardDoneState(ownerElement); + } + /** * Create a new action {@link ActionUsage} inside the given element which should be an {@link ActionUsage} or an {@link ActionDefinition}. * 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 9f0967d15..51e58cba5 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 @@ -25,10 +25,12 @@ import org.eclipse.syson.diagram.common.view.DescriptionFinder; import org.eclipse.syson.diagram.common.view.nodes.DecisionActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DoneActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ForkActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.JoinActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.MergeActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StartActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.StartStateNodeDescriptionProvider; import org.eclipse.syson.sysml.AcceptActionUsage; import org.eclipse.syson.sysml.ActionUsage; import org.eclipse.syson.sysml.AllocationUsage; @@ -328,6 +330,8 @@ private boolean isRegularNodeDescription(NodeDescription nodeDesc) { isSpecial = isSpecial || this.descriptionNameGenerator.getNodeName(ForkActionNodeDescriptionProvider.FORK_ACTION_NAME).equals(nodeDesc.getName()); isSpecial = isSpecial || this.descriptionNameGenerator.getNodeName(MergeActionNodeDescriptionProvider.MERGE_ACTION_NAME).equals(nodeDesc.getName()); isSpecial = isSpecial || this.descriptionNameGenerator.getNodeName(DecisionActionNodeDescriptionProvider.DECISION_ACTION_NAME).equals(nodeDesc.getName()); + isSpecial = isSpecial || this.descriptionNameGenerator.getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME).equals(nodeDesc.getName()); + isSpecial = isSpecial || this.descriptionNameGenerator.getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME).equals(nodeDesc.getName()); return !isSpecial; } diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/DoneStateNodeToolProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/DoneStateNodeToolProvider.java new file mode 100644 index 000000000..38a0bcf99 --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/DoneStateNodeToolProvider.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2024, 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.tools; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.StateTransitionCompartmentNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.services.ViewCreateService; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ServiceMethod; + +/** + * Used to add the standard done state in states body for all diagrams. + * + * @author Jerome Gout + */ +public class DoneStateNodeToolProvider extends AbstractFreeFormCompartmentNodeToolProvider { + + public DoneStateNodeToolProvider(EClass ownerEClass, IDescriptionNameGenerator descriptionNameGenerator) { + super(ownerEClass, StateTransitionCompartmentNodeDescriptionProvider.STATE_COMPARTMENT_NAME, descriptionNameGenerator); + } + + @Override + protected String getNodeDescriptionName() { + return this.getDescriptionNameGenerator().getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME); + } + + @Override + protected String getCreationServiceCallExpression() { + return ServiceMethod.of0(ViewCreateService::addDoneState).aqlSelf(); + } + + @Override + protected String getLabel() { + return "New Done State"; + } + + @Override + protected String getIconPath() { + return "/icons/done_action.svg"; + } +} diff --git a/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/StartStateNodeToolProvider.java b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/StartStateNodeToolProvider.java new file mode 100644 index 000000000..c83ce401e --- /dev/null +++ b/backend/views/syson-diagram-common-view/src/main/java/org/eclipse/syson/diagram/common/view/tools/StartStateNodeToolProvider.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2024, 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.tools; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.syson.diagram.common.view.nodes.StartStateNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.StateTransitionCompartmentNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.services.ViewCreateService; +import org.eclipse.syson.util.IDescriptionNameGenerator; +import org.eclipse.syson.util.ServiceMethod; + +/** + * Used to add the standard start state in states body for all diagrams. + * + * @author Jerome Gout + */ +public class StartStateNodeToolProvider extends AbstractFreeFormCompartmentNodeToolProvider { + + public StartStateNodeToolProvider(EClass ownerEClass, IDescriptionNameGenerator descriptionNameGenerator) { + super(ownerEClass, StateTransitionCompartmentNodeDescriptionProvider.STATE_COMPARTMENT_NAME, descriptionNameGenerator); + } + + @Override + protected String getNodeDescriptionName() { + return this.getDescriptionNameGenerator().getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME); + } + + @Override + protected String getCreationServiceCallExpression() { + return ServiceMethod.of0(ViewCreateService::addStartState).aqlSelf(); + } + + @Override + protected String getLabel() { + return "New Start State"; + } + + @Override + protected String getIconPath() { + return "/icons/start_action.svg"; + } +} 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 d22934ea1..248ca9f72 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 @@ -47,6 +47,7 @@ import org.eclipse.syson.diagram.common.view.nodes.CompartmentItemNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DecisionActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DoneActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ForkActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ImportedPackageNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.InheritedCompartmentItemNodeDescriptionProvider; @@ -56,6 +57,7 @@ import org.eclipse.syson.diagram.common.view.nodes.SatisfyRequirementCompartmentItemNodeDescription; import org.eclipse.syson.diagram.common.view.nodes.SatisfyRequirementCompartmentNodeDescription; import org.eclipse.syson.diagram.common.view.nodes.StartActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.StartStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StateTransitionCompartmentNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StatesCompartmentItemNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StatesCompartmentNodeDescriptionProvider; @@ -781,6 +783,8 @@ private List> createAllCustomNodeDescripti customNodeDescriptionProviders.add(new StakeholderNodeDescriptionProvider(colorProvider)); customNodeDescriptionProviders.add(new SubjectNodeDescriptionProvider(colorProvider)); customNodeDescriptionProviders.add(new ImportedPackageNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); + customNodeDescriptionProviders.add(new StartStateNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); + customNodeDescriptionProviders.add(new DoneStateNodeDescriptionProvider(colorProvider, this.getDescriptionNameGenerator())); return customNodeDescriptionProviders; } 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 eade01314..3cceba6bb 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 @@ -30,11 +30,13 @@ import org.eclipse.syson.diagram.common.view.nodes.AbstractDefinitionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DecisionActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DoneActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ForkActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.JoinActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.MergeActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StartActionNodeDescriptionProvider; import org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService; +import org.eclipse.syson.diagram.common.view.nodes.StartStateNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator; import org.eclipse.syson.standard.diagrams.view.SDVDiagramDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.services.SDVNodeToolSectionSwitch; @@ -123,6 +125,8 @@ protected List getAllNodeDescriptions(IViewDiagramElementFinder cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(ForkActionNodeDescriptionProvider.FORK_ACTION_NAME)).ifPresent(allNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(MergeActionNodeDescriptionProvider.MERGE_ACTION_NAME)).ifPresent(allNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(DecisionActionNodeDescriptionProvider.DECISION_ACTION_NAME)).ifPresent(allNodes::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME)).ifPresent(allNodes::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME)).ifPresent(allNodes::add); return allNodes; } 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 2e60eff45..12bee5bff 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 @@ -30,11 +30,13 @@ import org.eclipse.syson.diagram.common.view.nodes.AbstractUsageNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DecisionActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.DoneActionNodeDescriptionProvider; +import org.eclipse.syson.diagram.common.view.nodes.DoneStateNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.ForkActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.JoinActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.MergeActionNodeDescriptionProvider; import org.eclipse.syson.diagram.common.view.nodes.StartActionNodeDescriptionProvider; import org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService; +import org.eclipse.syson.diagram.common.view.nodes.StartStateNodeDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator; import org.eclipse.syson.standard.diagrams.view.SDVDiagramDescriptionProvider; import org.eclipse.syson.standard.diagrams.view.services.SDVNodeToolSectionSwitch; @@ -135,6 +137,8 @@ protected List getAllNodeDescriptions(IViewDiagramElementFinder cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(ForkActionNodeDescriptionProvider.FORK_ACTION_NAME)).ifPresent(allNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(MergeActionNodeDescriptionProvider.MERGE_ACTION_NAME)).ifPresent(allNodes::add); cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(DecisionActionNodeDescriptionProvider.DECISION_ACTION_NAME)).ifPresent(allNodes::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME)).ifPresent(allNodes::add); + cache.getNodeDescription(this.getDescriptionNameGenerator().getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME)).ifPresent(allNodes::add); return allNodes; } diff --git a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java index 546187c3e..e167e01fc 100644 --- a/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java +++ b/backend/views/syson-standard-diagrams-view/src/main/java/org/eclipse/syson/standard/diagrams/view/services/SDVNodeToolSectionSwitch.java @@ -34,6 +34,7 @@ import org.eclipse.syson.diagram.common.view.tools.ConnectionDefinitionEndCompartmentNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.DecisionActionNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.DoneActionNodeToolProvider; +import org.eclipse.syson.diagram.common.view.tools.DoneStateNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.ExhibitStateWithReferenceNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.ForkActionNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.InterfaceDefinitionEndCompartmentNodeToolProvider; @@ -58,6 +59,7 @@ import org.eclipse.syson.diagram.common.view.tools.SetAsViewToolProvider; import org.eclipse.syson.diagram.common.view.tools.StakeholdersCompartmentNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.StartActionNodeToolProvider; +import org.eclipse.syson.diagram.common.view.tools.StartStateNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.StateSubactionNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.StateTransitionCompartmentNodeToolProvider; import org.eclipse.syson.diagram.common.view.tools.SubjectCompartmentNodeToolProvider; @@ -741,6 +743,8 @@ public List caseRequirementDefinition(RequirementDefinition obj @Override public List caseStateDefinition(StateDefinition object) { var sections = this.toolDescriptionService.createDefaultNodeToolSections(); + this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StartStateNodeToolProvider(object.eClass(), this.descriptionNameGenerator).create(this.cache)); + this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new DoneStateNodeToolProvider(object.eClass(), this.descriptionNameGenerator).create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(false, false).create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(true, false).create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(false, true).create(this.cache)); @@ -768,6 +772,8 @@ public List caseStateDefinition(StateDefinition object) { @Override public List caseStateUsage(StateUsage object) { var sections = this.toolDescriptionService.createDefaultNodeToolSections(); + this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StartStateNodeToolProvider(object.eClass(), this.descriptionNameGenerator).create(this.cache)); + this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new DoneStateNodeToolProvider(object.eClass(), this.descriptionNameGenerator).create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(false, false).create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(true, false).create(this.cache)); this.toolDescriptionService.addNodeTool(sections, ToolConstants.BEHAVIOR, new StateTransitionCompartmentNodeToolProvider(false, true).create(this.cache));