Skip to content

Commit 8306f9a

Browse files
committed
[enh] Move view edge services to new service architecture
Signed-off-by: Axel RICHARD <axel.richard@obeo.fr>
1 parent de12bba commit 8306f9a

16 files changed

Lines changed: 660 additions & 577 deletions

File tree

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
=== Breaking changes
1010

1111
- [services] As part of the migration to the new diagram service architecture, the methods that were exposed by `ViewToolService` (which has been deleted) are now split between `org.eclipse.syson.diagram.services.aql.DiagramMutationAQLService` for mutation services, `org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService` for diagram query and tool precondition services, and `org.eclipse.syson.tree.services.aql.TreeQueryAQLService` for selection dialog tree query services.
12+
- [services] As part of the migration to the new diagram service architecture, the methods that were exposed by `ViewEdgeService` (which has been deleted) are now split between `org.eclipse.syson.diagram.services.aql.DiagramMutationAQLService` for edge reconnection mutation services, `org.eclipse.syson.diagram.services.aql.DiagramQueryAQLService` for diagram graphical query services, and `org.eclipse.syson.model.services.aql.ModelQueryAQLService` for model and metamodel query services.
1213

1314
=== Dependency update
1415

backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramMutationElementService.java

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Set;
2222
import java.util.stream.Collectors;
2323

24+
import org.eclipse.emf.common.util.EList;
2425
import org.eclipse.sirius.components.collaborative.diagrams.DiagramContext;
2526
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramDescriptionService;
2627
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramQueryService;
@@ -44,6 +45,8 @@
4445
import org.eclipse.syson.services.NodeDescriptionService;
4546
import org.eclipse.syson.services.UtilService;
4647
import org.eclipse.syson.services.api.SiriusWebCoreServices;
48+
import org.eclipse.syson.sysml.ActionUsage;
49+
import org.eclipse.syson.sysml.AllocationUsage;
4750
import org.eclipse.syson.sysml.BindingConnectorAsUsage;
4851
import org.eclipse.syson.sysml.ConnectionUsage;
4952
import org.eclipse.syson.sysml.Connector;
@@ -53,17 +56,26 @@
5356
import org.eclipse.syson.sysml.Feature;
5457
import org.eclipse.syson.sysml.FeatureMembership;
5558
import org.eclipse.syson.sysml.FlowUsage;
59+
import org.eclipse.syson.sysml.IncludeUseCaseUsage;
5660
import org.eclipse.syson.sysml.InterfaceUsage;
61+
import org.eclipse.syson.sysml.Membership;
5762
import org.eclipse.syson.sysml.Namespace;
63+
import org.eclipse.syson.sysml.OwningMembership;
5864
import org.eclipse.syson.sysml.PartUsage;
5965
import org.eclipse.syson.sysml.PortUsage;
66+
import org.eclipse.syson.sysml.ReferenceSubsetting;
67+
import org.eclipse.syson.sysml.ReferenceUsage;
6068
import org.eclipse.syson.sysml.RequirementUsage;
6169
import org.eclipse.syson.sysml.SatisfyRequirementUsage;
6270
import org.eclipse.syson.sysml.StateDefinition;
6371
import org.eclipse.syson.sysml.StateUsage;
72+
import org.eclipse.syson.sysml.Succession;
73+
import org.eclipse.syson.sysml.SuccessionAsUsage;
6474
import org.eclipse.syson.sysml.SysmlFactory;
6575
import org.eclipse.syson.sysml.Type;
76+
import org.eclipse.syson.sysml.TransitionUsage;
6677
import org.eclipse.syson.sysml.Usage;
78+
import org.eclipse.syson.sysml.UseCaseUsage;
6779
import org.eclipse.syson.sysml.ViewUsage;
6880
import org.eclipse.syson.sysml.metamodel.helper.EMFUtils;
6981
import org.eclipse.syson.sysml.metamodel.services.ElementInitializerSwitch;
@@ -701,6 +713,185 @@ public SatisfyRequirementUsage reconnectSatisfyRequirementTarget(SatisfyRequirem
701713
return sru;
702714
}
703715

716+
/**
717+
* Reconnects the source of an allocate edge.
718+
*
719+
* @param allocationUsage
720+
* the allocate edge to reconnect
721+
* @param newSource
722+
* the new source
723+
* @return the allocate edge
724+
*/
725+
public Element reconnectSourceAllocateEdge(AllocationUsage allocationUsage, Element newSource) {
726+
if (newSource instanceof Usage usage) {
727+
var features = this.getAllocateEdgeFeatures(allocationUsage);
728+
if (features.size() == 2) {
729+
var reference = features.getFirst().getOwnedReferenceSubsetting();
730+
if (reference != null) {
731+
reference.setReferencedFeature(usage);
732+
}
733+
}
734+
}
735+
return allocationUsage;
736+
}
737+
738+
/**
739+
* Reconnects the target of an allocate edge.
740+
*
741+
* @param allocationUsage
742+
* the allocate edge to reconnect
743+
* @param newTarget
744+
* the new target
745+
* @return the allocate edge
746+
*/
747+
public Element reconnectTargetAllocateEdge(AllocationUsage allocationUsage, Element newTarget) {
748+
if (newTarget instanceof Usage usage) {
749+
var features = this.getAllocateEdgeFeatures(allocationUsage);
750+
if (features.size() == 2) {
751+
var reference = features.get(1).getOwnedReferenceSubsetting();
752+
if (reference != null) {
753+
reference.setReferencedFeature(usage);
754+
}
755+
}
756+
}
757+
return allocationUsage;
758+
}
759+
760+
/**
761+
* Reconnects the source of a succession edge.
762+
*
763+
* @param succession
764+
* the succession edge
765+
* @param oldSource
766+
* the previous source
767+
* @param newSource
768+
* the new source
769+
* @return the succession edge
770+
*/
771+
public Element reconnectSourceSuccessionEdge(SuccessionAsUsage succession, Element oldSource, Element newSource) {
772+
EList<Feature> ends = succession.getConnectorEnd();
773+
if (!ends.isEmpty()) {
774+
this.setConnectorEndFeature(ends.getFirst(), newSource);
775+
}
776+
return succession;
777+
}
778+
779+
/**
780+
* Reconnects the target of a succession edge.
781+
*
782+
* @param succession
783+
* the succession edge
784+
* @param oldTarget
785+
* the previous target
786+
* @param newTarget
787+
* the new target
788+
* @return the succession edge
789+
*/
790+
public Element reconnectTargetSuccessionEdge(SuccessionAsUsage succession, Element oldTarget, Element newTarget) {
791+
EList<Feature> ends = succession.getConnectorEnd();
792+
if (ends.size() > 1) {
793+
this.setConnectorEndFeature(ends.get(1), newTarget);
794+
}
795+
return succession;
796+
}
797+
798+
/**
799+
* Reconnects the source of a transition edge.
800+
*
801+
* @param transition
802+
* the transition to reconnect
803+
* @param newSource
804+
* the new source
805+
* @return the transition
806+
*/
807+
public TransitionUsage reconnectSourceTransitionEdge(TransitionUsage transition, ActionUsage newSource) {
808+
if (newSource instanceof TransitionUsage || !this.isValidTransitionTarget(newSource, transition.getTarget())) {
809+
this.feedbackMessageService.addFeedbackMessage(new Message("Invalid new source for transition", MessageLevel.WARNING));
810+
return transition;
811+
}
812+
transition.getOwnedMembership().stream()
813+
.filter(Membership.class::isInstance)
814+
.findFirst()
815+
.ifPresent(membership -> membership.setMemberElement(newSource));
816+
817+
Succession succession = transition.getSuccession();
818+
succession.getFeatureMembership().stream()
819+
.filter(EndFeatureMembership.class::isInstance)
820+
.map(EndFeatureMembership.class::cast)
821+
.findFirst()
822+
.ifPresent(endFeatureMembership -> endFeatureMembership.getOwnedRelatedElement().stream()
823+
.findFirst()
824+
.ifPresent(feature -> feature.getOwnedRelationship().stream()
825+
.filter(ReferenceSubsetting.class::isInstance)
826+
.map(ReferenceSubsetting.class::cast)
827+
.findFirst()
828+
.ifPresent(referenceSubsetting -> referenceSubsetting.setReferencedFeature(newSource))));
829+
return transition;
830+
}
831+
832+
/**
833+
* Reconnects the target of a transition edge.
834+
*
835+
* @param transition
836+
* the transition to reconnect
837+
* @param newTarget
838+
* the new target
839+
* @return the transition
840+
*/
841+
public TransitionUsage reconnectTargetTransitionEdge(TransitionUsage transition, ActionUsage newTarget) {
842+
if (newTarget instanceof TransitionUsage || !this.isValidTransitionTarget(transition.getSource(), newTarget)) {
843+
this.feedbackMessageService.addFeedbackMessage(new Message("Invalid new target for transition", MessageLevel.WARNING));
844+
return transition;
845+
}
846+
Succession succession = transition.getSuccession();
847+
List<EndFeatureMembership> successionFeatureMemberships = succession.getFeatureMembership().stream()
848+
.filter(EndFeatureMembership.class::isInstance)
849+
.map(EndFeatureMembership.class::cast)
850+
.toList();
851+
if (successionFeatureMemberships.size() > 1) {
852+
successionFeatureMemberships.get(1).getOwnedRelatedElement().stream()
853+
.findFirst()
854+
.ifPresent(feature -> feature.getOwnedRelationship().stream()
855+
.filter(ReferenceSubsetting.class::isInstance)
856+
.map(ReferenceSubsetting.class::cast)
857+
.findFirst()
858+
.ifPresent(referenceSubsetting -> referenceSubsetting.setReferencedFeature(newTarget)));
859+
}
860+
return transition;
861+
}
862+
863+
/**
864+
* Reconnects the source of an include use case edge.
865+
*
866+
* @param includeUseCaseUsage
867+
* the include use case edge
868+
* @param newSource
869+
* the new source
870+
* @return the include use case edge
871+
*/
872+
public IncludeUseCaseUsage reconnectSourceIncludeUseCaseUsage(IncludeUseCaseUsage includeUseCaseUsage, UseCaseUsage newSource) {
873+
OwningMembership owningMembership = includeUseCaseUsage.getOwningMembership();
874+
newSource.getOwnedRelationship().add(owningMembership);
875+
return includeUseCaseUsage;
876+
}
877+
878+
/**
879+
* Reconnects the target of an include use case edge.
880+
*
881+
* @param includeUseCaseUsage
882+
* the include use case edge
883+
* @param newTarget
884+
* the new target
885+
* @return the include use case edge
886+
*/
887+
public IncludeUseCaseUsage reconnectTargetIncludeUseCaseUsage(IncludeUseCaseUsage includeUseCaseUsage, UseCaseUsage newTarget) {
888+
ReferenceSubsetting referenceSubsetting = includeUseCaseUsage.getOwnedReferenceSubsetting();
889+
if (referenceSubsetting != null) {
890+
referenceSubsetting.setReferencedFeature(newTarget);
891+
}
892+
return includeUseCaseUsage;
893+
}
894+
704895
/**
705896
* Creates a {@link BindingConnectorAsUsage}.
706897
*
@@ -927,4 +1118,45 @@ private Optional<Namespace> getConnectorContainer(Node sourceNode, Node targetNo
9271118
}
9281119
return namespaceOwner;
9291120
}
1121+
1122+
private List<Feature> getAllocateEdgeFeatures(AllocationUsage allocationUsage) {
1123+
return allocationUsage.getOwnedFeatureMembership().stream()
1124+
.filter(EndFeatureMembership.class::isInstance)
1125+
.map(EndFeatureMembership.class::cast)
1126+
.flatMap(endFeatureMembership -> endFeatureMembership.getOwnedRelatedElement().stream())
1127+
.filter(Feature.class::isInstance)
1128+
.map(Feature.class::cast)
1129+
.toList();
1130+
}
1131+
1132+
private void setConnectorEndFeature(Feature sourceEnd, Element newTargetFeature) {
1133+
if (sourceEnd instanceof ReferenceUsage referenceUsage) {
1134+
ReferenceSubsetting referenceSubsetting = sourceEnd.getOwnedReferenceSubsetting();
1135+
if (referenceSubsetting == null || referenceSubsetting.isIsImplied()) {
1136+
referenceSubsetting = SysmlFactory.eINSTANCE.createReferenceSubsetting();
1137+
referenceSubsetting.setSubsettingFeature(referenceUsage);
1138+
}
1139+
this.getAction(newTargetFeature).ifPresent(referenceSubsetting::setReferencedFeature);
1140+
}
1141+
}
1142+
1143+
private Optional<ActionUsage> getAction(Element element) {
1144+
Optional<ActionUsage> result = Optional.empty();
1145+
if (element instanceof Membership membership) {
1146+
if (membership.getMemberElement() instanceof ActionUsage actionUsage) {
1147+
result = Optional.of(actionUsage);
1148+
}
1149+
} else if (element instanceof ActionUsage actionUsage) {
1150+
result = Optional.of(actionUsage);
1151+
}
1152+
return result;
1153+
}
1154+
1155+
private boolean isValidTransitionTarget(Element source, Element target) {
1156+
boolean sameParent = false;
1157+
if (source instanceof ActionUsage sourceAction && target instanceof ActionUsage targetAction) {
1158+
sameParent = sourceAction.getOwner() == targetAction.getOwner();
1159+
}
1160+
return sameParent && !this.utilService.isParallelState(source.getOwner());
1161+
}
9301162
}

backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryGraphicalService.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.eclipse.syson.diagram.services;
1414

1515
import java.util.List;
16+
import java.util.Objects;
1617

1718
import org.eclipse.sirius.components.diagrams.elements.NodeElementProps;
1819
import org.eclipse.sirius.components.diagrams.renderer.DiagramRenderingCache;
@@ -46,6 +47,29 @@ public boolean isNotAncestorOf(org.eclipse.sirius.components.representations.Ele
4647
return !this.isAncestorOf(parentNodeElement, childNodeElement, cache);
4748
}
4849

50+
/**
51+
* Returns {@code true} if both elements are contained in the same graphical container.
52+
*
53+
* @param source
54+
* the graphical source element
55+
* @param target
56+
* the graphical target element
57+
* @param cache
58+
* the rendering cache used in the current rendering process
59+
* @return {@code true} if both elements share the same graphical container
60+
*/
61+
public boolean isInSameGraphicalContainer(org.eclipse.sirius.components.representations.Element source,
62+
org.eclipse.sirius.components.representations.Element target, DiagramRenderingCache cache) {
63+
if (source.getProps() instanceof NodeElementProps sourceNodeProps
64+
&& target.getProps() instanceof NodeElementProps targetNodeProps) {
65+
String sourceParentId = this.getParentId(cache, sourceNodeProps);
66+
String targetParentId = this.getParentId(cache, targetNodeProps);
67+
return (sourceParentId == null && targetParentId == null)
68+
|| (sourceParentId != null && sourceParentId.equals(targetParentId));
69+
}
70+
return true;
71+
}
72+
4973
/**
5074
* Returns {@code true} if {@code parentNodeElement} is an ancestor of {@code childNodeElement}.
5175
*
@@ -74,4 +98,17 @@ private boolean isAncestorOf(org.eclipse.sirius.components.representations.Eleme
7498
}
7599
return result;
76100
}
101+
102+
private String getParentId(DiagramRenderingCache cache, NodeElementProps nodeElementProps) {
103+
return cache.getParent(nodeElementProps.getId())
104+
.map(org.eclipse.sirius.components.representations.Element::getProps)
105+
.map(props -> {
106+
if (props instanceof NodeElementProps parentNodeProps) {
107+
return parentNodeProps.getId();
108+
}
109+
return null;
110+
})
111+
.filter(Objects::nonNull)
112+
.orElse(null);
113+
}
77114
}

0 commit comments

Comments
 (0)