Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ A new compartment named _satisfy requirements_ has also been added to `PartDefin
- https://github.com/eclipse-syson/syson/issues/1786[#1786] [export] Implement textual export of `RequirementConstraintMembership`.
- https://github.com/eclipse-syson/syson/issues/1771[#1740] [services] Add `IDetailViewHelpTextProvider` service in order to add help text to properties widgets
- https://github.com/eclipse-syson/syson/issues/1738[#1738] [diagrams] Add `ConnectionUsage` as edges in _General View_ diagram.
- https://github.com/eclipse-syson/syson/issues/1747[#1747] [diagrams] Most new elements created by invoking a tool on a diagram are now automatically selected

== v2025.12.0

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 Obeo.
* 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
Expand All @@ -18,7 +18,6 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -28,24 +27,11 @@
import org.eclipse.acceleo.query.runtime.IService;
import org.eclipse.acceleo.query.runtime.Query;
import org.eclipse.acceleo.query.runtime.QueryParsing;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.sirius.components.interpreter.SimpleCrossReferenceProvider;
import org.eclipse.sirius.components.view.ChangeContext;
import org.eclipse.sirius.components.view.Operation;
import org.eclipse.sirius.components.view.RepresentationDescription;
import org.eclipse.sirius.components.view.View;
import org.eclipse.sirius.components.view.diagram.ConditionalEdgeStyle;
import org.eclipse.sirius.components.view.diagram.ConditionalNodeStyle;
import org.eclipse.sirius.components.view.diagram.CreateView;
import org.eclipse.sirius.components.view.diagram.DiagramDescription;
import org.eclipse.sirius.components.view.diagram.EdgeDescription;
import org.eclipse.sirius.components.view.diagram.InsideLabelDescription;
import org.eclipse.sirius.components.view.diagram.InsideLabelStyle;
import org.eclipse.sirius.components.view.diagram.LabelEditTool;
import org.eclipse.sirius.components.view.diagram.NodeDescription;
import org.eclipse.sirius.components.view.diagram.NodeTool;
import org.eclipse.sirius.components.view.diagram.OutsideLabelDescription;
import org.eclipse.sirius.components.view.diagram.SelectionDialogDescription;
import org.eclipse.sirius.components.view.diagram.Tool;
import org.eclipse.sirius.components.view.ViewPackage;
import org.eclipse.syson.sysml.helper.EMFUtils;
import org.eclipse.syson.util.AQLConstants;

Expand All @@ -66,7 +52,7 @@ public JavaServiceIsCalledChecker(View view) {


this.aqlServiceNames = new HashSet<>();
Collection<String> aqlExpressions = this.collectAQLExpressionsInView(view);
Collection<String> aqlExpressions = this.collectAQLExpressions(view);

List<String> aqlBodyExpressions = aqlExpressions.stream()
.filter(expression -> expression != null && !expression.isBlank())
Expand All @@ -93,140 +79,20 @@ public void check(Method service) {
.contains(service.getName());
}

private Collection<String> collectAQLExpressionsInView(View view) {
private Collection<String> collectAQLExpressions(EObject eObject) {
Set<String> expressions = new HashSet<>();
for (RepresentationDescription description : view.getDescriptions()) {
if (description instanceof DiagramDescription diagramDescription) {
expressions.addAll(this.collectAQLExpressionsInDiagramDescription(diagramDescription));
}
}
return expressions;
}

private Collection<String> collectAQLExpressionsInDiagramDescription(DiagramDescription diagramDescription) {
Set<String> expressions = new HashSet<>();

expressions.add(diagramDescription.getPreconditionExpression());

final List<Tool> allDiagramTools = EMFUtils.allContainedObjectOfType(diagramDescription, Tool.class).toList();

for (Tool diagramTool : allDiagramTools) {
expressions.add(diagramTool.getPreconditionExpression());
for (Operation bodyOperation : diagramTool.getBody()) {
EMFUtils.allContainedObjectOfType(bodyOperation, ChangeContext.class)
.map(ChangeContext::getExpression)
.forEach(expressions::add);
}
if (diagramTool instanceof NodeTool nodeTool) {
if (nodeTool.getDialogDescription() instanceof SelectionDialogDescription selectionDialogDescription) {
expressions.add(selectionDialogDescription.getSelectionDialogTreeDescription().getElementsExpression());
expressions.add(selectionDialogDescription.getSelectionDialogTreeDescription().getChildrenExpression());
expressions.add(selectionDialogDescription.getSelectionDialogTreeDescription().getIsSelectableExpression());
}
}
}

EMFUtils.allContainedObjectOfType(diagramDescription, NodeDescription.class)
.map(this::collectAQLExpressionsInNodeDescription)
.forEach(expressions::addAll);
EMFUtils.allContainedObjectOfType(diagramDescription, EdgeDescription.class)
.map(this::collectAQLExpressionsInEdgeDescription)
.forEach(expressions::addAll);

EMFUtils.allContainedObjectOfType(diagramDescription, ConditionalNodeStyle.class)
.map(ConditionalNodeStyle::getCondition)
.forEach(expressions::add);
EMFUtils.allContainedObjectOfType(diagramDescription, ConditionalEdgeStyle.class)
.map(ConditionalEdgeStyle::getCondition)
.forEach(expressions::add);

return expressions;
}

private Collection<String> collectAQLExpressionsInNodeDescription(NodeDescription nodeDescription) {
Set<String> expressions = new HashSet<>();
Optional.ofNullable(nodeDescription.getSemanticCandidatesExpression())
.map(expressions::add);

Optional.ofNullable(nodeDescription.getInsideLabel()).map(InsideLabelDescription::getLabelExpression)
.map(expressions::add);

Optional.ofNullable(nodeDescription.getInsideLabel()).map(InsideLabelDescription::getStyle)
.map(InsideLabelStyle::getShowIconExpression)
.map(expressions::add);

Optional.ofNullable(nodeDescription.getOutsideLabels())
.ifPresent(outsideLabelDescriptions -> outsideLabelDescriptions.stream().map(OutsideLabelDescription::getLabelExpression).forEach(expressions::add));

Optional.ofNullable(nodeDescription.getIsHiddenByDefaultExpression())
.map(expressions::add);

Optional.ofNullable(nodeDescription.getPreconditionExpression())
.map(expressions::add);


List<Tool> nodeTools = Optional.ofNullable(nodeDescription.getPalette()).stream()
.flatMap(palette -> EMFUtils.allContainedObjectOfType(palette, Tool.class))
.toList();

for (Tool nodeTool : nodeTools) {
expressions.add(nodeTool.getPreconditionExpression());
if (nodeTool instanceof LabelEditTool labelEditTool) {
expressions.add(labelEditTool.getInitialDirectEditLabelExpression());
}
if (nodeTool instanceof NodeTool createNodeTool) {
if (createNodeTool.getDialogDescription() instanceof SelectionDialogDescription selectionDialogDescription) {
expressions.add(selectionDialogDescription.getSelectionDialogTreeDescription().getElementsExpression());
}
}
for (Operation bodyOperation : nodeTool.getBody()) {
EMFUtils.allContainedObjectOfType(bodyOperation, ChangeContext.class)
.forEach(changeContext -> expressions.add(changeContext.getExpression()));
EMFUtils.allContainedObjectOfType(bodyOperation, CreateView.class)
.forEach(changeContext -> expressions.add(changeContext.getParentViewExpression()));
}
}
this.collectAQLExpressions(eObject, expressions);
return expressions;
}

private Collection<String> collectAQLExpressionsInEdgeDescription(EdgeDescription edgeDescription) {
Set<String> expressions = new HashSet<>();
Optional.ofNullable(edgeDescription.getSemanticCandidatesExpression())
.map(expressions::add);

Optional.ofNullable(edgeDescription.getBeginLabelExpression())
.map(expressions::add);

Optional.ofNullable(edgeDescription.getCenterLabelExpression())
.map(expressions::add);

Optional.ofNullable(edgeDescription.getEndLabelExpression())
.map(expressions::add);

Optional.ofNullable(edgeDescription.getSourceExpression())
.map(expressions::add);

Optional.ofNullable(edgeDescription.getTargetExpression())
.map(expressions::add);

Optional.ofNullable(edgeDescription.getPreconditionExpression())
.map(expressions::add);

final List<Tool> allEdgeTools = EMFUtils.allContainedObjectOfType(edgeDescription, Tool.class).toList();

for (Tool edgeTool : allEdgeTools) {
expressions.add(edgeTool.getPreconditionExpression());
if (edgeTool instanceof LabelEditTool labelEditTool) {
expressions.add(labelEditTool.getInitialDirectEditLabelExpression());
}
for (Operation bodyOperation : edgeTool.getBody()) {
EMFUtils.allContainedObjectOfType(bodyOperation, ChangeContext.class)
.forEach(changeContext -> expressions.add(changeContext.getExpression()));
EMFUtils.allContainedObjectOfType(bodyOperation, CreateView.class)
.forEach(changeContext -> expressions.add(changeContext.getParentViewExpression()));
}
}
return expressions;
private void collectAQLExpressions(EObject eObject, Set<String> expressions) {
// All interpreted expressions on the eOject itself
eObject.eClass().getEAllStructuralFeatures().stream()
.filter(EAttribute.class::isInstance)
.map(EAttribute.class::cast)
.filter(attr -> attr.getEType() == ViewPackage.Literals.INTERPRETED_EXPRESSION)
.forEach(expressionAttribute -> expressions.add((String) eObject.eGet(expressionAttribute)));
// Recurse on all its descendants
eObject.eAllContents().forEachRemaining(o -> this.collectAQLExpressions(o, expressions));
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 Obeo.
* 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
Expand All @@ -12,8 +12,6 @@
*******************************************************************************/
package org.eclipse.syson.diagram.common.view.tools;

import java.util.List;

import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.diagrams.Node;
Expand All @@ -25,9 +23,9 @@
import org.eclipse.sirius.components.view.diagram.NodeTool;
import org.eclipse.sirius.components.view.diagram.SelectionDialogDescription;
import org.eclipse.sirius.components.view.emf.diagram.ViewDiagramDescriptionConverter;
import org.eclipse.syson.diagram.common.view.services.ViewNodeService;
import org.eclipse.syson.diagram.services.aql.DiagramMutationAQLService;
import org.eclipse.syson.util.AQLConstants;
import org.eclipse.syson.util.AQLUtils;
import org.eclipse.syson.util.ServiceMethod;

/**
Expand All @@ -37,6 +35,8 @@
*/
public abstract class AbstractCompartmentNodeToolProvider implements INodeToolProvider {

private static final String NEW_INSTANCE = "newInstance";

protected final DiagramBuilders diagramBuilderHelper = new DiagramBuilders();

protected final ViewBuilders viewBuilderHelper = new ViewBuilders();
Expand Down Expand Up @@ -77,8 +77,8 @@ public NodeTool create(IViewDiagramElementFinder cache) {
ChangeContextBuilder revealOperation;
if (this.revealOnCreate()) {
revealOperation = this.viewBuilderHelper.newChangeContext()
.expression(AQLUtils.getServiceCallExpression(Node.SELECTED_NODE, "revealCompartment",
List.of("self", DiagramContext.DIAGRAM_CONTEXT, IEditingContext.EDITING_CONTEXT, ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE)));
.expression(ServiceMethod.of4(ViewNodeService::revealCompartment).aql(Node.SELECTED_NODE, AQLConstants.SELF, DiagramContext.DIAGRAM_CONTEXT, IEditingContext.EDITING_CONTEXT,
ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE));
} else {
revealOperation = this.viewBuilderHelper.newChangeContext().expression(AQLConstants.AQL_SELF);
}
Expand All @@ -87,19 +87,25 @@ public NodeTool create(IViewDiagramElementFinder cache) {
.expression(ServiceMethod.of4(DiagramMutationAQLService::expose).aqlSelf(IEditingContext.EDITING_CONTEXT, DiagramContext.DIAGRAM_CONTEXT, Node.SELECTED_NODE,
ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE));

var creationCompartmentItemServiceCall = this.viewBuilderHelper.newChangeContext()
.expression(this.getServiceCallExpression())
var exposeAndRevealNewInstance = this.viewBuilderHelper.newChangeContext()
.expression(AQLConstants.AQL + NEW_INSTANCE)
.children(addToExposedElements.build(), revealOperation.build());

var letNewInstance = this.viewBuilderHelper.newLet()
.variableName(NEW_INSTANCE)
.valueExpression(this.getServiceCallExpression())
.children(exposeAndRevealNewInstance.build());

var rootChangContext = this.viewBuilderHelper.newChangeContext()
.expression(AQLConstants.AQL_SELF)
.children(creationCompartmentItemServiceCall.build())
.children(letNewInstance.build())
.build();

return builder.name(this.getNodeToolName())
.iconURLsExpression(this.getNodeToolIconURLsExpression())
.body(rootChangContext)
.preconditionExpression(this.getPreconditionExpression())
.elementsToSelectExpression(AQLConstants.AQL + NEW_INSTANCE)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 Obeo.
* 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
Expand All @@ -12,8 +12,6 @@
*******************************************************************************/
package org.eclipse.syson.diagram.common.view.tools;

import java.util.List;

import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.diagrams.Node;
Expand All @@ -23,8 +21,10 @@
import org.eclipse.sirius.components.view.builder.providers.INodeToolProvider;
import org.eclipse.sirius.components.view.diagram.NodeTool;
import org.eclipse.sirius.components.view.emf.diagram.ViewDiagramDescriptionConverter;
import org.eclipse.syson.diagram.common.view.services.ViewCreateService;
import org.eclipse.syson.diagram.common.view.services.ViewNodeService;
import org.eclipse.syson.diagram.services.aql.DiagramMutationAQLService;
import org.eclipse.syson.util.AQLUtils;
import org.eclipse.syson.util.AQLConstants;
import org.eclipse.syson.util.ServiceMethod;

/**
Expand All @@ -34,6 +34,8 @@
*/
public class ActionFlowCompartmentNodeToolProvider implements INodeToolProvider {

private static final String NEW_INSTANCE = "newInstance";

private final DiagramBuilders diagramBuilderHelper = new DiagramBuilders();

private final ViewBuilders viewBuilderHelper = new ViewBuilders();
Expand All @@ -47,18 +49,24 @@ public NodeTool create(IViewDiagramElementFinder cache) {
ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE));

var revealOperation = this.viewBuilderHelper.newChangeContext()
.expression(
AQLUtils.getServiceCallExpression(Node.SELECTED_NODE, "revealCompartment",
List.of("self", DiagramContext.DIAGRAM_CONTEXT, IEditingContext.EDITING_CONTEXT, ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE)));
.expression(ServiceMethod.of4(ViewNodeService::revealCompartment).aql(Node.SELECTED_NODE, AQLConstants.SELF, DiagramContext.DIAGRAM_CONTEXT, IEditingContext.EDITING_CONTEXT,
ViewDiagramDescriptionConverter.CONVERTED_NODES_VARIABLE));

var creationServiceCall = this.viewBuilderHelper.newChangeContext()
.expression(AQLUtils.getSelfServiceCallExpression("createSubActionUsage"))
.expression(AQLConstants.AQL + NEW_INSTANCE)
.children(addToExposedElements.build(), revealOperation.build())
.build();

var letNewInstance = this.viewBuilderHelper.newLet()
.variableName(NEW_INSTANCE)
.valueExpression(ServiceMethod.of0(ViewCreateService::createSubActionUsage).aqlSelf())
.children(creationServiceCall)
.build();

return builder.name("New Action")
.iconURLsExpression("/icons/full/obj16/ActionUsage.svg")
.body(creationServiceCall)
.body(letNewInstance)
.elementsToSelectExpression(AQLConstants.AQL + NEW_INSTANCE)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ a|image::release-notes-enumeration-definition-after.png[Enumeration definition n
- In diagrams, when creating an element from a compartment, it will not be displayed by default on the diagram, but only in the compartment.
- In the _Advanced_ tab of the _Details_ view, _isComposite_ and _isReference_ properties (checkbox widgets) now have a help text.
- In diagrams, a new tool named `Reference Subsetting` is available in the palette to create `ReferenceSubsetting` relationships between `Usage` elements.
- In diagrams, many new tools now automatically select the `Elements` they create or expose on a diagram.
This makes it easy to start editing newly created elements to give them proper names by starting to type directly when the new element appears.


== Technical details
Expand Down
Loading
Loading