|
| 1 | +/******************************************************************************* |
| 2 | + * Copyright (c) 2026 Obeo. |
| 3 | + * This program and the accompanying materials |
| 4 | + * are made available under the terms of the Eclipse Public License v2.0 |
| 5 | + * which accompanies this distribution, and is available at |
| 6 | + * https://www.eclipse.org/legal/epl-2.0/ |
| 7 | + * |
| 8 | + * SPDX-License-Identifier: EPL-2.0 |
| 9 | + * |
| 10 | + * Contributors: |
| 11 | + * Obeo - initial API and implementation |
| 12 | + *******************************************************************************/ |
| 13 | +package org.eclipse.syson.diagram.services; |
| 14 | + |
| 15 | +import java.util.List; |
| 16 | +import java.util.Objects; |
| 17 | +import java.util.Optional; |
| 18 | +import java.util.stream.Stream; |
| 19 | + |
| 20 | +import org.eclipse.emf.common.util.EList; |
| 21 | +import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext; |
| 22 | +import org.eclipse.sirius.components.core.api.IEditingContext; |
| 23 | +import org.eclipse.sirius.components.core.api.IObjectSearchService; |
| 24 | +import org.eclipse.sirius.components.diagrams.Edge; |
| 25 | +import org.eclipse.sirius.components.diagrams.IDiagramElement; |
| 26 | +import org.eclipse.sirius.components.diagrams.Node; |
| 27 | +import org.eclipse.syson.sysml.AnnotatingElement; |
| 28 | +import org.eclipse.syson.sysml.Element; |
| 29 | +import org.eclipse.syson.sysml.ViewUsage; |
| 30 | +import org.springframework.stereotype.Service; |
| 31 | + |
| 32 | +/** |
| 33 | + * Query services related to annotating nodes. |
| 34 | + * |
| 35 | + * @author arichard |
| 36 | + */ |
| 37 | +@Service |
| 38 | +public class DiagramQueryAnnotatingService { |
| 39 | + |
| 40 | + private final IObjectSearchService objectSearchService; |
| 41 | + |
| 42 | + public DiagramQueryAnnotatingService(IObjectSearchService objectSearchService) { |
| 43 | + this.objectSearchService = Objects.requireNonNull(objectSearchService); |
| 44 | + } |
| 45 | + |
| 46 | + /** |
| 47 | + * Returns {@code true} if the provided annotated element of the given {@code element} is represented on the |
| 48 | + * diagram, {@code false} otherwise. |
| 49 | + */ |
| 50 | + public boolean showAnnotatingNode(Element element, DiagramContext diagramContext, IEditingContext editingContext) { |
| 51 | + boolean displayAnnotatingNode = false; |
| 52 | + if (element instanceof AnnotatingElement ae && diagramContext != null && editingContext != null) { |
| 53 | + EList<Element> annotatedElements = ae.getAnnotatedElement(); |
| 54 | + IDiagramElement matchingDiagramElement = null; |
| 55 | + |
| 56 | + displayAnnotatingNode = this.isAnnotatingNodeOnRoot(diagramContext, editingContext, annotatedElements); |
| 57 | + |
| 58 | + if (!displayAnnotatingNode) { |
| 59 | + for (Node node : diagramContext.diagram().getNodes()) { |
| 60 | + matchingDiagramElement = this.getOneMatchingAnnotatedNode(node, annotatedElements, diagramContext, editingContext); |
| 61 | + if (matchingDiagramElement != null) { |
| 62 | + displayAnnotatingNode = true; |
| 63 | + break; |
| 64 | + } |
| 65 | + } |
| 66 | + } |
| 67 | + if (!displayAnnotatingNode) { |
| 68 | + for (Edge edge : diagramContext.diagram().getEdges()) { |
| 69 | + matchingDiagramElement = this.getOneMatchingAnnotatedEdge(edge, annotatedElements, diagramContext, editingContext); |
| 70 | + if (matchingDiagramElement != null) { |
| 71 | + displayAnnotatingNode = true; |
| 72 | + break; |
| 73 | + } |
| 74 | + } |
| 75 | + } |
| 76 | + } else { |
| 77 | + displayAnnotatingNode = true; |
| 78 | + } |
| 79 | + return displayAnnotatingNode; |
| 80 | + } |
| 81 | + |
| 82 | + private boolean isAnnotatingNodeOnRoot(DiagramContext diagramContext, IEditingContext editingContext, EList<Element> annotatedElements) { |
| 83 | + boolean isAnnotatingNodeOnRoot = false; |
| 84 | + String diagramTargetObjectId = diagramContext.diagram().getTargetObjectId(); |
| 85 | + Element diagramTargetObject = this.objectSearchService.getObject(editingContext, diagramTargetObjectId).stream() |
| 86 | + .filter(Element.class::isInstance) |
| 87 | + .map(Element.class::cast) |
| 88 | + .findFirst() |
| 89 | + .orElse(null); |
| 90 | + if (diagramTargetObject instanceof ViewUsage viewUsage) { |
| 91 | + if (annotatedElements.contains(viewUsage)) { |
| 92 | + isAnnotatingNodeOnRoot = true; |
| 93 | + } else { |
| 94 | + isAnnotatingNodeOnRoot = annotatedElements.contains(viewUsage.getOwner()); |
| 95 | + } |
| 96 | + } |
| 97 | + return isAnnotatingNodeOnRoot; |
| 98 | + } |
| 99 | + |
| 100 | + private Edge getOneMatchingAnnotatedEdge(Edge edge, List<Element> annotatedElements, DiagramContext diagramContext, IEditingContext editingContext) { |
| 101 | + Edge matchingAnnotatedEdge = null; |
| 102 | + Optional<Object> semanticNodeOpt = this.objectSearchService.getObject(editingContext, edge.getTargetObjectId()); |
| 103 | + if (semanticNodeOpt.isPresent()) { |
| 104 | + if (annotatedElements.contains(semanticNodeOpt.get())) { |
| 105 | + boolean isDeletingAnnotatingEdge = diagramContext.viewDeletionRequests().stream() |
| 106 | + .anyMatch(viewDeletionRequest -> Objects.equals(viewDeletionRequest.getElementId(), edge.getId())); |
| 107 | + if (!isDeletingAnnotatingEdge) { |
| 108 | + matchingAnnotatedEdge = edge; |
| 109 | + } |
| 110 | + return matchingAnnotatedEdge; |
| 111 | + } |
| 112 | + } |
| 113 | + return matchingAnnotatedEdge; |
| 114 | + } |
| 115 | + |
| 116 | + private Node getOneMatchingAnnotatedNode(Node node, List<Element> annotatedElements, DiagramContext diagramContext, IEditingContext editingContext) { |
| 117 | + Node matchingAnnotatedNode = null; |
| 118 | + Optional<Object> semanticNodeOpt = this.objectSearchService.getObject(editingContext, node.getTargetObjectId()); |
| 119 | + if (semanticNodeOpt.isPresent()) { |
| 120 | + if (annotatedElements.contains(semanticNodeOpt.get())) { |
| 121 | + boolean isDeletingAnnotatingNode = diagramContext.viewDeletionRequests().stream() |
| 122 | + .anyMatch(viewDeletionRequest -> Objects.equals(viewDeletionRequest.getElementId(), node.getId())); |
| 123 | + if (!isDeletingAnnotatingNode) { |
| 124 | + matchingAnnotatedNode = node; |
| 125 | + } |
| 126 | + return matchingAnnotatedNode; |
| 127 | + } |
| 128 | + } |
| 129 | + matchingAnnotatedNode = this.getFirstMatchingChildAnnotatedNode(node, annotatedElements, diagramContext, editingContext); |
| 130 | + return matchingAnnotatedNode; |
| 131 | + } |
| 132 | + |
| 133 | + private Node getFirstMatchingChildAnnotatedNode(Node node, List<Element> annotatedElements, DiagramContext diagramContext, IEditingContext editingContext) { |
| 134 | + List<Node> childrenNodes = Stream.concat(node.getChildNodes().stream(), node.getBorderNodes().stream()).toList(); |
| 135 | + for (Node childNode : childrenNodes) { |
| 136 | + Node matchingChildAnnotatedNode = this.getOneMatchingAnnotatedNode(childNode, annotatedElements, diagramContext, editingContext); |
| 137 | + if (matchingChildAnnotatedNode != null) { |
| 138 | + return matchingChildAnnotatedNode; |
| 139 | + } |
| 140 | + } |
| 141 | + return null; |
| 142 | + } |
| 143 | +} |
0 commit comments