Skip to content

Commit a873eb0

Browse files
mcharfadisbegaudeau
authored andcommitted
[5782] Add support for tools on a multiple selection in diagrams
Bug: #5782 Signed-off-by: Michaël Charfadi <michael.charfadi@obeosoft.com>
1 parent d3eeffd commit a873eb0

File tree

82 files changed

+2945
-1100
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2945
-1100
lines changed

CHANGELOG.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ You can use `IViewToolFinder` to find a node or edge tool in a view dsl.
2626
- https://github.com/eclipse-sirius/sirius-web/issues/3486[#3486] Nodes and edges have a new `deletable` attribute in the GraphQL Schema that custom nodes must consider in their converter.
2727
On the backend, the node and edge's `deleteHandler` can now be `null` if no semantic deletion tool is defined for this element.
2828
`IViewNodeDeleteHandler`, which only existed to provide a non-null handler able to tell if there was a semantic deletion tool, has been removed.
29+
https://github.com/eclipse-sirius/sirius-web/issues/5782[#5782] [diagram] The input `GetPaletteInput` will now require a list of diagram element ids instead of a single one to retrieve a palette for multiple elements selected at once.
30+
In a similar manner, `InvokeSingleClickOnDiagramElementToolInput` will now ask for a list of diagram element ids to execute a tool on multiple elements are once
2931

3032

3133
=== Dependency update
@@ -49,6 +51,8 @@ On the backend, the node and edge's `deleteHandler` can now be `null` if no sema
4951
The command relies on Elasticsearch's _query string_, which provides syntactical constructs to query fields, use wildcards, regular expressions, and fuzziness.
5052
You can check the https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-query-string-query#query-string-syntax[documentation] for more information, including a list of reserved characters and how to escape them.
5153
The command is only visible if Elasticsearch is up and running.
54+
https://github.com/eclipse-sirius/sirius-web/issues/5782[#5782] [diagram] Add the ability to execute tools on a selection of multiple elements
55+
https://github.com/eclipse-sirius/sirius-web/issues/5782[#5782] [view] Add the concept of GroupPalette in the diagram view dsl to provide tools to execute while multiple elements are selected
5256

5357

5458
=== Improvements

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/api/IPaletteProvider.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
*******************************************************************************/
1313
package org.eclipse.sirius.components.collaborative.diagrams.api;
1414

15+
import java.util.List;
16+
1517
import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext;
1618
import org.eclipse.sirius.components.collaborative.diagrams.dto.Palette;
1719
import org.eclipse.sirius.components.core.api.IEditingContext;
@@ -25,7 +27,7 @@
2527
*/
2628
public interface IPaletteProvider {
2729

28-
boolean canHandle(DiagramDescription diagramDescription);
30+
boolean canHandle(IEditingContext editingContext, DiagramContext diagramContext, DiagramDescription diagramDescription, List<String> diagramElementIds);
2931

30-
Palette handle(IEditingContext editingContext, DiagramContext diagramContext, DiagramDescription diagramDescription, Object diagramElementDescription, Object diagramElement, Object targetElement);
32+
Palette handle(IEditingContext editingContext, DiagramContext diagramContext, DiagramDescription diagramDescription, List<Object> diagramElements);
3133
}

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/dto/GetPaletteInput.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2022, 2023 Obeo.
2+
* Copyright (c) 2022, 2025 Obeo.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
1212
*******************************************************************************/
1313
package org.eclipse.sirius.components.collaborative.diagrams.dto;
1414

15+
import java.util.List;
1516
import java.util.UUID;
1617

1718
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramInput;
@@ -21,5 +22,5 @@
2122
*
2223
* @author arichard
2324
*/
24-
public record GetPaletteInput(UUID id, String editingContextId, String representationId, String diagramElementId) implements IDiagramInput {
25+
public record GetPaletteInput(UUID id, String editingContextId, String representationId, List<String> diagramElementIds) implements IDiagramInput {
2526
}

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/dto/InvokeSingleClickOnDiagramElementToolInput.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019, 2024 Obeo and others.
2+
* Copyright (c) 2019, 2025 Obeo and others.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -22,6 +22,6 @@
2222
*
2323
* @author pcdavid
2424
*/
25-
public record InvokeSingleClickOnDiagramElementToolInput(UUID id, String editingContextId, String representationId, String diagramElementId, String toolId, double startingPositionX,
25+
public record InvokeSingleClickOnDiagramElementToolInput(UUID id, String editingContextId, String representationId, List<String> diagramElementIds, String toolId, double startingPositionX,
2626
double startingPositionY, List<ToolVariable> variables) implements IDiagramInput {
2727
}

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/handlers/GetPaletteEventHandler.java

Lines changed: 17 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,27 @@
1616
import java.util.Objects;
1717
import java.util.Optional;
1818

19-
import io.micrometer.core.instrument.Counter;
20-
import io.micrometer.core.instrument.MeterRegistry;
2119
import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
2220
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
2321
import org.eclipse.sirius.components.collaborative.api.Monitoring;
2422
import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext;
25-
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramDescriptionService;
2623
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramEventHandler;
2724
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramInput;
2825
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramQueryService;
2926
import org.eclipse.sirius.components.collaborative.diagrams.api.IPaletteProvider;
3027
import org.eclipse.sirius.components.collaborative.diagrams.dto.GetPaletteInput;
3128
import org.eclipse.sirius.components.collaborative.diagrams.dto.GetPaletteSuccessPayload;
32-
import org.eclipse.sirius.components.collaborative.diagrams.dto.Palette;
3329
import org.eclipse.sirius.components.collaborative.messages.ICollaborativeMessageService;
3430
import org.eclipse.sirius.components.core.api.ErrorPayload;
3531
import org.eclipse.sirius.components.core.api.IEditingContext;
36-
import org.eclipse.sirius.components.core.api.IObjectSearchService;
3732
import org.eclipse.sirius.components.core.api.IPayload;
3833
import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService;
3934
import org.eclipse.sirius.components.diagrams.Diagram;
40-
import org.eclipse.sirius.components.diagrams.Edge;
41-
import org.eclipse.sirius.components.diagrams.Node;
4235
import org.eclipse.sirius.components.diagrams.description.DiagramDescription;
4336
import org.springframework.stereotype.Service;
37+
38+
import io.micrometer.core.instrument.Counter;
39+
import io.micrometer.core.instrument.MeterRegistry;
4440
import reactor.core.publisher.Sinks.Many;
4541
import reactor.core.publisher.Sinks.One;
4642

@@ -56,23 +52,16 @@ public class GetPaletteEventHandler implements IDiagramEventHandler {
5652

5753
private final IDiagramQueryService diagramQueryService;
5854

59-
private final IDiagramDescriptionService diagramDescriptionService;
60-
61-
private final IObjectSearchService objectSearchService;
62-
6355
private final List<IPaletteProvider> paletteProviders;
6456

6557
private final ICollaborativeMessageService messageService;
6658

6759
private final Counter counter;
6860

6961
public GetPaletteEventHandler(IRepresentationDescriptionSearchService representationDescriptionSearchService, IDiagramQueryService diagramQueryService,
70-
IDiagramDescriptionService diagramDescriptionService, IObjectSearchService objectSearchService, List<IPaletteProvider> paletteProviders, ICollaborativeMessageService messageService,
71-
MeterRegistry meterRegistry) {
62+
List<IPaletteProvider> paletteProviders, ICollaborativeMessageService messageService, MeterRegistry meterRegistry) {
7263
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
7364
this.diagramQueryService = Objects.requireNonNull(diagramQueryService);
74-
this.diagramDescriptionService = Objects.requireNonNull(diagramDescriptionService);
75-
this.objectSearchService = Objects.requireNonNull(objectSearchService);
7665
this.paletteProviders = Objects.requireNonNull(paletteProviders);
7766
this.messageService = Objects.requireNonNull(messageService);
7867

@@ -92,33 +81,32 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDesc
9281

9382
String message = this.messageService.invalidInput(diagramInput.getClass().getSimpleName(), GetPaletteInput.class.getSimpleName());
9483
IPayload payload = new ErrorPayload(diagramInput.id(), message);
95-
Palette palette = null;
9684

9785
ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, editingContext.getId(), diagramInput);
9886

99-
if (diagramInput instanceof GetPaletteInput toolSectionsInput) {
100-
String diagramElementId = toolSectionsInput.diagramElementId();
101-
87+
if (diagramInput instanceof GetPaletteInput getPaletteInput) {
88+
var diagramElementIds = getPaletteInput.diagramElementIds();
10289
Diagram diagram = diagramContext.diagram();
10390
var optionalDiagramDescription = this.representationDescriptionSearchService.findById(editingContext, diagram.getDescriptionId())
10491
.filter(DiagramDescription.class::isInstance)
10592
.map(DiagramDescription.class::cast);
10693
if (optionalDiagramDescription.isPresent()) {
10794
DiagramDescription diagramDescription = optionalDiagramDescription.get();
108-
var optionalPaletteProvider = this.paletteProviders.stream().filter(paletteProvider -> paletteProvider.canHandle(diagramDescription)).findFirst();
109-
var optionalTargetElement = this.findTargetElement(diagram, diagramElementId, editingContext);
110-
var optionalDiagramElement = this.findDiagramElement(diagram, diagramElementId);
111-
var optionalDiagramElementDescription = this.findDiagramElementDescription(diagram, diagramElementId, diagramDescription, optionalDiagramElement.orElse(null));
112-
113-
if (optionalPaletteProvider.isPresent() && optionalTargetElement.isPresent() && optionalDiagramElementDescription.isPresent()) {
95+
var optionalPaletteProvider = this.paletteProviders.stream()
96+
.filter(paletteProvider -> paletteProvider.canHandle(editingContext, diagramContext, diagramDescription, diagramElementIds))
97+
.findFirst();
98+
if (optionalPaletteProvider.isPresent()) {
11499
IPaletteProvider paletteProvider = optionalPaletteProvider.get();
115-
palette = paletteProvider.handle(editingContext, diagramContext, diagramDescription, optionalDiagramElementDescription.get(), optionalDiagramElement.orElse(null), optionalTargetElement.get());
100+
101+
var diagramElements = diagramElementIds.stream()
102+
.map(diagramElementId -> this.findDiagramElement(diagram, diagramElementId))
103+
.flatMap(Optional::stream)
104+
.toList();
105+
var palette = paletteProvider.handle(editingContext, diagramContext, diagramDescription, diagramElements);
106+
payload = new GetPaletteSuccessPayload(diagramInput.id(), palette);
116107
}
117108
}
118109
}
119-
if (palette != null) {
120-
payload = new GetPaletteSuccessPayload(diagramInput.id(), palette);
121-
}
122110
payloadSink.tryEmitValue(payload);
123111
changeDescriptionSink.tryEmitNext(changeDescription);
124112
}
@@ -141,49 +129,5 @@ private Optional<Object> findDiagramElement(Diagram diagram, String diagramEleme
141129
return Optional.ofNullable(diagramElement);
142130
}
143131

144-
private Optional<Object> findDiagramElementDescription(Diagram diagram, String diagramElementId, DiagramDescription diagramDescription, Object diagramElement) {
145-
Object diagramElementDescription = null;
146-
147-
boolean appliesToRootDiagram = diagram.getId().equals(diagramElementId);
148-
if (appliesToRootDiagram) {
149-
diagramElementDescription = diagramDescription;
150-
} else if (diagramElement instanceof Node) {
151-
String descriptionId = ((Node) diagramElement).getDescriptionId();
152-
var optionalNodeDescription = this.diagramDescriptionService.findNodeDescriptionById(diagramDescription, descriptionId);
153-
if (optionalNodeDescription.isPresent()) {
154-
diagramElementDescription = optionalNodeDescription.get();
155-
}
156-
} else if (diagramElement instanceof Edge) {
157-
String descriptionId = ((Edge) diagramElement).getDescriptionId();
158-
var optionalEdgeDescription = this.diagramDescriptionService.findEdgeDescriptionById(diagramDescription, descriptionId);
159-
if (optionalEdgeDescription.isPresent()) {
160-
diagramElementDescription = optionalEdgeDescription.get();
161-
}
162-
}
163-
return Optional.ofNullable(diagramElementDescription);
164-
}
165132

166-
private Optional<Object> findTargetElement(Diagram diagram, String diagramElementId, IEditingContext editingContext) {
167-
String targetObjectId = null;
168-
boolean appliesToRootDiagram = diagram.getId().equals(diagramElementId);
169-
if (appliesToRootDiagram) {
170-
targetObjectId = diagram.getTargetObjectId();
171-
} else {
172-
var findNodeById = this.diagramQueryService.findNodeById(diagram, diagramElementId);
173-
if (findNodeById.isPresent()) {
174-
Node node = findNodeById.get();
175-
targetObjectId = node.getTargetObjectId();
176-
} else {
177-
var findEdgeById = this.diagramQueryService.findEdgeById(diagram, diagramElementId);
178-
if (findEdgeById.isPresent()) {
179-
Edge edge = findEdgeById.get();
180-
targetObjectId = edge.getTargetObjectId();
181-
}
182-
}
183-
}
184-
if (targetObjectId != null) {
185-
return this.objectSearchService.getObject(editingContext, targetObjectId);
186-
}
187-
return Optional.empty();
188-
}
189133
}

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/handlers/InvokeSingleClickOnDiagramElementToolEventHandler.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.eclipse.sirius.components.collaborative.diagrams.dto.InvokeSingleClickOnDiagramElementToolInput;
2828
import org.eclipse.sirius.components.collaborative.diagrams.dto.InvokeSingleClickOnDiagramElementToolSuccessPayload;
2929
import org.eclipse.sirius.components.collaborative.diagrams.messages.ICollaborativeDiagramMessageService;
30+
import org.eclipse.sirius.components.collaborative.diagrams.services.ISingleClickOnMultipleDiagramElementHandler;
3031
import org.eclipse.sirius.components.collaborative.diagrams.services.ISingleClickOnOneDiagramElementHandler;
3132
import org.eclipse.sirius.components.core.api.ErrorPayload;
3233
import org.eclipse.sirius.components.core.api.IEditingContext;
@@ -60,11 +61,14 @@ public class InvokeSingleClickOnDiagramElementToolEventHandler implements IDiagr
6061

6162
private final List<ISingleClickOnOneDiagramElementHandler> singleClickOnOneDiagramElementHandlers;
6263

64+
private final List<ISingleClickOnMultipleDiagramElementHandler> singleClickOnMultipleDiagramElementHandlers;
65+
6366
private final Counter counter;
6467

65-
public InvokeSingleClickOnDiagramElementToolEventHandler(ICollaborativeDiagramMessageService messageService, List<ISingleClickOnOneDiagramElementHandler> singleClickOnOneDiagramElementHandlers, MeterRegistry meterRegistry) {
68+
public InvokeSingleClickOnDiagramElementToolEventHandler(ICollaborativeDiagramMessageService messageService, List<ISingleClickOnOneDiagramElementHandler> singleClickOnOneDiagramElementHandlers, List<ISingleClickOnMultipleDiagramElementHandler> singleClickOnMultipleDiagramElementHandlers, MeterRegistry meterRegistry) {
6669
this.messageService = Objects.requireNonNull(messageService);
6770
this.singleClickOnOneDiagramElementHandlers = Objects.requireNonNull(singleClickOnOneDiagramElementHandlers);
71+
this.singleClickOnMultipleDiagramElementHandlers = Objects.requireNonNull(singleClickOnMultipleDiagramElementHandlers);
6872
this.counter = Counter.builder(Monitoring.EVENT_HANDLER)
6973
.tag(Monitoring.NAME, this.getClass().getSimpleName())
7074
.register(meterRegistry);
@@ -84,11 +88,20 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDesc
8488
ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, diagramInput.representationId(), diagramInput);
8589

8690
if (diagramInput instanceof InvokeSingleClickOnDiagramElementToolInput input) {
87-
IStatus status = this.singleClickOnOneDiagramElementHandlers.stream()
88-
.filter(handler -> handler.canHandle(editingContext, diagramContext.diagram(), input.toolId(), input.diagramElementId()))
89-
.findFirst()
90-
.map(handler -> handler.execute(editingContext, diagramContext.diagram(), input.toolId(), input.diagramElementId(), input.variables()))
91-
.orElse(new Failure(this.messageService.handlerNotFound()));
91+
IStatus status;
92+
if (input.diagramElementIds().size() == 1) {
93+
status = this.singleClickOnOneDiagramElementHandlers.stream()
94+
.filter(handler -> handler.canHandle(editingContext, diagramContext.diagram(), input.toolId(), input.diagramElementIds().get(0)))
95+
.findFirst()
96+
.map(handler -> handler.execute(editingContext, diagramContext.diagram(), input.toolId(), input.diagramElementIds().get(0), input.variables()))
97+
.orElse(new Failure("No handler found"));
98+
} else {
99+
status = this.singleClickOnMultipleDiagramElementHandlers.stream()
100+
.filter(handler -> handler.canHandle(editingContext, diagramContext.diagram(), input.toolId(), input.diagramElementIds()))
101+
.findFirst()
102+
.map(handler -> handler.execute(editingContext, diagramContext.diagram(), input.toolId(), input.diagramElementIds(), input.variables()))
103+
.orElse(new Failure("No handler found"));
104+
}
92105

93106
if (status instanceof Success success) {
94107
WorkbenchSelection newSelection = null;

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/providers/GenericDiagramToolReferencePositionProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ public boolean canHandle(IInput diagramInput) {
4040
@Override
4141
public ReferencePosition getReferencePosition(IInput diagramInput, DiagramContext diagramContext) {
4242
ReferencePosition referencePosition = null;
43-
if (diagramInput instanceof InvokeSingleClickOnDiagramElementToolInput input) {
44-
String parentId = this.getParentId(diagramContext, input.diagramElementId());
43+
if (diagramInput instanceof InvokeSingleClickOnDiagramElementToolInput input && !input.diagramElementIds().isEmpty()) {
44+
String parentId = this.getParentId(diagramContext, input.diagramElementIds().get(0));
4545
referencePosition = new ReferencePosition(parentId, new Position(input.startingPositionX(), input.startingPositionY()), input.getClass().getSimpleName());
4646
} else if (diagramInput instanceof DropNodesInput input) {
4747
referencePosition = new ReferencePosition(input.targetElementId(), new Position(input.x(), input.y()), input.getClass().getSimpleName());

0 commit comments

Comments
 (0)