Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,28 @@ public List<StateUsage> 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
*/
public List<EObject> 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<EObject> 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}.
Expand Down Expand Up @@ -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 <code>States</code>.
*
* @param eObject
* an object to access to the library resources.
*
* @return the standard start StateUsage defined in the <code>States</code> library.
*/
public StateUsage retrieveStandardStartState(Element eObject) {
return this.findByNameAndTypeInStandardLibraries(eObject, StateUsage.class, "States::StateAction::start");
}

/**
* Retrieve the done action defined inside the standard library <code>Actions</code>.
*
Expand All @@ -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 <code>States</code>.
*
* @param eObject
* an object to access to the library resources.
*
* @return the standard done StateUsage defined in the <code>States</code> library.
*/
public ActionUsage retrieveStandardDoneState(Element eObject) {
return this.findByNameAndTypeInStandardLibraries(eObject, ActionUsage.class, "States::StateAction::done");
}

private <T extends Element> T findByNameAndTypeInStandardLibraries(Element context, Class<T> klass, String qualifiedName) {
return context.eResource().getResourceSet().getResources().stream()
.flatMap(resource -> this.getLibraries(resource, true).stream())
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -181,11 +183,13 @@ protected List<NodeDescription> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,9 @@ protected void addReusableCustomNodes(IViewDiagramElementFinder cache, List<Node
.ifPresent(childrenNodes::add);
cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(DoneActionNodeDescriptionProvider.DONE_ACTION_NAME))
.ifPresent(childrenNodes::add);
cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(StartStateNodeDescriptionProvider.START_STATE_NAME))
.ifPresent(childrenNodes::add);
cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(DoneStateNodeDescriptionProvider.DONE_STATE_NAME))
.ifPresent(childrenNodes::add);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*******************************************************************************
* 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.Objects;

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.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.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 ending node description of a state.
*
* @author Jerome Gout
*/
public class DoneStateNodeDescriptionProvider extends AbstractNodeDescriptionProvider {

public static final String DONE_STATE_NAME = "DoneState";

private final IDescriptionNameGenerator descriptionNameGenerator;

public DoneStateNodeDescriptionProvider(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("36")
.defaultHeightExpression("36")
.name(this.descriptionNameGenerator.getNodeName(DONE_STATE_NAME))
.semanticCandidatesExpression(ServiceMethod.of0(UtilService::retrieveStandardDoneState).aqlSelf())
.style(this.createImageNodeStyleDescription("images/done_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(DONE_STATE_NAME)).ifPresent(nodeDescription -> {
nodeDescription.setPalette(this.createNodePalette());
});
}

private NodePalette createNodePalette() {
return this.diagramBuilderHelper.newNodePalette()
.quickAccessTools(this.getDeleteFromDiagramTool())
.toolSections(this.defaultToolsFactory.createDefaultHideRevealNodeToolSection())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -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<EdgeTool>(this.getEdgeTools(cache));

return this.diagramBuilderHelper.newNodePalette()
.edgeTools(edgeTools.toArray(EdgeTool[]::new))
.quickAccessTools(this.getDeleteFromDiagramTool())
.toolSections(this.defaultToolsFactory.createDefaultHideRevealNodeToolSection())
.build();
}

private List<EdgeTool> 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<NodeDescription> getStartTargetDescriptions(IViewDiagramElementFinder cache) {
var targets = new ArrayList<NodeDescription>();
cache.getNodeDescription(this.descriptionNameGenerator.getNodeName(SysmlPackage.eINSTANCE.getStateUsage())).ifPresent(targets::add);
return targets;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
});
}
Expand Down Expand Up @@ -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));
Expand Down
Loading
Loading