From 8aa985df59fa55efb82421d24358a810853ac044 Mon Sep 17 00:00:00 2001 From: Jerome Gout Date: Thu, 18 Jul 2024 11:02:48 +0200 Subject: [PATCH] [3777] Support any object as semantic element in the tree representation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Add a virtual node for grouping super types of Entity nodes as an example Bug: https://github.com/eclipse-sirius/sirius-web/issues/3777 Signed-off-by: Jerome Gout Signed-off-by: Stéphane Bégaudeau --- CHANGELOG.adoc | 1 + .../ModelBrowsersDescriptionProvider.java | 10 ++ .../DeleteDocumentTreeItemEventHandler.java | 40 +++-- .../DeleteObjectTreeItemEventHandler.java | 41 +++-- ...eteRepresentationTreeItemEventHandler.java | 3 +- .../services/ExpandAllTreePathProvider.java | 91 ++++++---- .../services/ExplorerChildrenProvider.java | 24 +++ .../services/ExplorerDescriptionProvider.java | 75 ++++++++- .../services/ExplorerNavigationService.java | 33 +++- .../services/ExplorerTreePathProvider.java | 2 +- .../RenameDocumentTreeItemHandler.java | 56 ++++--- .../RenameObjectTreeItemEventHandler.java | 42 +++-- .../RenameRepresentationTreeItemHandler.java | 3 +- .../services/api/IDeleteTreeItemHandler.java | 3 +- .../api/IExplorerNavigationService.java | 5 +- .../services/api/IRenameTreeItemHandler.java | 3 +- ...orerNonSemanticElementControllerTests.java | 157 ++++++++++++++++++ .../handlers/DeleteTreeItemEventHandler.java | 3 +- .../handlers/RenameTreeItemEventHandler.java | 1 + .../trees/description/TreeDescription.java | 24 +++ 20 files changed, 495 insertions(+), 122 deletions(-) create mode 100644 packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f02c934d65..770e180ff6 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -101,6 +101,7 @@ A migration participant has been added to automatically keep compatible all diag - https://github.com/eclipse-sirius/sirius-web/issues/3801[#3801] Add an equivalent of IViewDiagramDescriptionSearchService for Form descriptions - https://github.com/eclipse-sirius/sirius-web/issues/3557[#3550] [sirius-web] Add an extension point to contribute setting pages - https://github.com/eclipse-sirius/sirius-web/issues/3776[#3776] [trees] Remove unwanted dependency from the reference widget in the explorer +- https://github.com/eclipse-sirius/sirius-web/issues/3777[#3777] [sirius-web] Add support for any kind of object as semantic element in the tree representation == v2024.7.0 diff --git a/packages/forms/backend/sirius-components-collaborative-widget-reference/src/main/java/org/eclipse/sirius/components/collaborative/widget/reference/browser/ModelBrowsersDescriptionProvider.java b/packages/forms/backend/sirius-components-collaborative-widget-reference/src/main/java/org/eclipse/sirius/components/collaborative/widget/reference/browser/ModelBrowsersDescriptionProvider.java index 38f74bc1ec..11c316b9dd 100644 --- a/packages/forms/backend/sirius-components-collaborative-widget-reference/src/main/java/org/eclipse/sirius/components/collaborative/widget/reference/browser/ModelBrowsersDescriptionProvider.java +++ b/packages/forms/backend/sirius-components-collaborative-widget-reference/src/main/java/org/eclipse/sirius/components/collaborative/widget/reference/browser/ModelBrowsersDescriptionProvider.java @@ -139,6 +139,7 @@ private TreeDescription getModelBrowserDescription(String descriptionId, Predica .canCreatePredicate(canCreatePredicate) .deleteHandler(this::getDeleteHandler) .renameHandler(this::getRenameHandler) + .treeItemObjectProvider(this::getTreeItemObject) .build(); } @@ -397,4 +398,13 @@ private IStatus getDeleteHandler(VariableManager variableManager) { private IStatus getRenameHandler(VariableManager variableManager, String newLabel) { return new Failure(""); } + + private Object getTreeItemObject(VariableManager variableManager) { + var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); + var optionalId = variableManager.get(TreeDescription.ID, String.class); + if (optionalId.isPresent() && optionalEditingContext.isPresent()) { + return this.objectService.getObject(optionalEditingContext.get(), optionalId.get()); + } + return null; + } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteDocumentTreeItemEventHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteDocumentTreeItemEventHandler.java index 437fbaf56d..f57f55bcde 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteDocumentTreeItemEventHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteDocumentTreeItemEventHandler.java @@ -12,21 +12,23 @@ *******************************************************************************/ package org.eclipse.sirius.web.application.views.explorer.services; -import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.core.api.IEditingContext; -import org.eclipse.sirius.components.emf.services.JSONResourceFactory; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; import org.eclipse.sirius.components.emf.services.api.IEMFEditingContext; import org.eclipse.sirius.components.representations.Failure; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; +import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.web.application.views.explorer.services.api.IDeleteTreeItemHandler; import org.springframework.stereotype.Service; @@ -38,29 +40,39 @@ @Service public class DeleteDocumentTreeItemEventHandler implements IDeleteTreeItemHandler { + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + public DeleteDocumentTreeItemEventHandler(IRepresentationDescriptionSearchService representationDescriptionSearchService) { + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); + } + @Override public boolean canHandle(IEditingContext editingContext, TreeItem treeItem) { return treeItem.getKind().equals(ExplorerDescriptionProvider.DOCUMENT_KIND); } @Override - public IStatus handle(IEditingContext editingContext, TreeItem treeItem) { + public IStatus handle(IEditingContext editingContext, TreeItem treeItem, Tree tree) { + var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + var optionalEditingDomain = Optional.of(editingContext) .filter(IEMFEditingContext.class::isInstance) .map(IEMFEditingContext.class::cast) .map(IEMFEditingContext::getDomain); - if (optionalEditingDomain.isPresent()) { - var editingDomain = optionalEditingDomain.get(); - ResourceSet resourceSet = editingDomain.getResourceSet(); - URI uri = new JSONResourceFactory().createResourceURI(treeItem.getId()); - - List resourcesToDelete = resourceSet.getResources().stream() - .filter(resource -> resource.getURI().equals(uri)) - .toList(); - resourcesToDelete.forEach(resourceSet.getResources()::remove); + if (optionalEditingDomain.isPresent() && optionalTreeDescription.isPresent()) { + var variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TreeDescription.ID, treeItem.getId()); - return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + var object = optionalTreeDescription.get().getTreeItemObjectProvider().apply(variableManager); + if (object instanceof Resource resource) { + ResourceSet resourceSet = optionalEditingDomain.get().getResourceSet(); + resourceSet.getResources().remove(resource); + return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + } } return new Failure(""); } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteObjectTreeItemEventHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteObjectTreeItemEventHandler.java index a875284d67..5b10f713a6 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteObjectTreeItemEventHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteObjectTreeItemEventHandler.java @@ -14,17 +14,19 @@ import java.util.Map; import java.util.Objects; -import java.util.Optional; import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.core.api.IEditService; import org.eclipse.sirius.components.core.api.IEditingContext; -import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; import org.eclipse.sirius.components.core.api.SemanticKindConstants; import org.eclipse.sirius.components.representations.Failure; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; +import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.web.application.views.explorer.services.api.IDeleteTreeItemHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,13 +42,13 @@ public class DeleteObjectTreeItemEventHandler implements IDeleteTreeItemHandler private final Logger logger = LoggerFactory.getLogger(DeleteObjectTreeItemEventHandler.class); - private final IObjectSearchService objectSearchService; - private final IEditService editService; - public DeleteObjectTreeItemEventHandler(IObjectSearchService objectSearchService, IEditService editService) { - this.objectSearchService = Objects.requireNonNull(objectSearchService); + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + public DeleteObjectTreeItemEventHandler(IEditService editService, IRepresentationDescriptionSearchService representationDescriptionSearchService) { this.editService = Objects.requireNonNull(editService); + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); } @Override @@ -55,16 +57,27 @@ public boolean canHandle(IEditingContext editingContext, TreeItem treeItem) { } @Override - public IStatus handle(IEditingContext editingContext, TreeItem treeItem) { - Optional optionalObject = this.objectSearchService.getObject(editingContext, treeItem.getId()); - if (optionalObject.isPresent()) { - Object object = optionalObject.get(); - this.editService.delete(object); + public IStatus handle(IEditingContext editingContext, TreeItem treeItem, Tree tree) { + IStatus result = new Failure(""); + var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + + if (optionalTreeDescription.isPresent()) { + var variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TreeDescription.ID, treeItem.getId()); - return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + var object = optionalTreeDescription.get().getTreeItemObjectProvider().apply(variableManager); + if (object != null) { + this.editService.delete(object); + result = new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + } else { + this.logger.warn("The object with the id {} does not exist", treeItem.getId()); + } } else { - this.logger.warn("The object with the id {} does not exist", treeItem.getId()); + this.logger.warn("Unable to retrieve the tree description with the id {}", tree.getDescriptionId()); } - return new Failure(""); + return result; } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteRepresentationTreeItemEventHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteRepresentationTreeItemEventHandler.java index 2bd6a0d2f7..587b75c4ab 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteRepresentationTreeItemEventHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/DeleteRepresentationTreeItemEventHandler.java @@ -21,6 +21,7 @@ import org.eclipse.sirius.components.representations.IRepresentation; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; import org.eclipse.sirius.web.application.views.explorer.services.api.IDeleteTreeItemHandler; import org.springframework.stereotype.Service; @@ -39,7 +40,7 @@ public boolean canHandle(IEditingContext editingContext, TreeItem treeItem) { } @Override - public IStatus handle(IEditingContext editingContext, TreeItem treeItem) { + public IStatus handle(IEditingContext editingContext, TreeItem treeItem, Tree tree) { Map parameters = new HashMap<>(); parameters.put(EditingContextEventProcessor.REPRESENTATION_ID, treeItem.getId()); return new Success(ChangeKind.REPRESENTATION_TO_DELETE, parameters); diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java index 0cd3863a3a..2375984521 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java @@ -14,9 +14,10 @@ import java.util.LinkedHashSet; import java.util.Objects; -import java.util.Optional; import java.util.Set; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.sirius.components.collaborative.trees.api.IExpandAllTreePathProvider; import org.eclipse.sirius.components.collaborative.trees.dto.ExpandAllTreePathInput; import org.eclipse.sirius.components.collaborative.trees.dto.ExpandAllTreePathSuccessPayload; @@ -24,10 +25,12 @@ import org.eclipse.sirius.components.core.api.IContentService; import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.core.api.IIdentityService; -import org.eclipse.sirius.components.core.api.IObjectSearchService; import org.eclipse.sirius.components.core.api.IPayload; -import org.eclipse.sirius.components.emf.services.api.IEMFEditingContext; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; +import org.eclipse.sirius.components.domain.Entity; +import org.eclipse.sirius.components.representations.VariableManager; import org.eclipse.sirius.components.trees.Tree; +import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerNavigationService; import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.services.api.IRepresentationDataSearchService; import org.springframework.stereotype.Service; @@ -40,8 +43,6 @@ @Service public class ExpandAllTreePathProvider implements IExpandAllTreePathProvider { - private final IObjectSearchService objectSearchService; - private final IIdentityService identityService; private final IContentService contentService; @@ -50,11 +51,13 @@ public class ExpandAllTreePathProvider implements IExpandAllTreePathProvider { private final IRepresentationDataSearchService representationDataSearchService; - public ExpandAllTreePathProvider(IObjectSearchService objectSearchService, IIdentityService identityService, IContentService contentService, IExplorerNavigationService explorerNavigationService, IRepresentationDataSearchService representationDataSearchService) { - this.objectSearchService = Objects.requireNonNull(objectSearchService); + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + public ExpandAllTreePathProvider(IIdentityService identityService, IContentService contentService, IExplorerNavigationService explorerNavigationService, IRepresentationDescriptionSearchService representationDescriptionSearchService, IRepresentationDataSearchService representationDataSearchService) { this.identityService = Objects.requireNonNull(identityService); this.contentService = Objects.requireNonNull(contentService); this.explorerNavigationService = Objects.requireNonNull(explorerNavigationService); + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); this.representationDataSearchService = Objects.requireNonNull(representationDataSearchService); } @@ -67,45 +70,47 @@ public boolean canHandle(Tree tree) { public IPayload handle(IEditingContext editingContext, Tree tree, ExpandAllTreePathInput input) { int maxDepth = 0; String treeItemId = input.treeItemId(); + Set treeItemIdsToExpand = new LinkedHashSet<>(); - var object = this.objectSearchService.getObject(editingContext, treeItemId); - if (object.isPresent()) { + var object = this.getTreeItemObject(editingContext, treeItemId, tree); + if (object instanceof EObject) { // We need to get the current depth of the tree item - var itemAncestors = this.explorerNavigationService.getAncestors(editingContext, treeItemId); + var itemAncestors = this.explorerNavigationService.getAncestors(editingContext, treeItemId, tree); maxDepth = itemAncestors.size(); - maxDepth = this.addAllContents(editingContext, treeItemId, maxDepth, treeItemIdsToExpand); - } else { + maxDepth = this.addAllContents(editingContext, treeItemId, maxDepth, treeItemIdsToExpand, tree); + } else if (object instanceof Resource resource) { // The object may be a document - var optionalEditingDomain = Optional.of(editingContext).filter(IEMFEditingContext.class::isInstance) - .map(IEMFEditingContext.class::cast) - .map(IEMFEditingContext::getDomain); - - if (optionalEditingDomain.isPresent()) { - var optionalResource = optionalEditingDomain.get().getResourceSet().getResources().stream() - .filter(resource -> treeItemId.equals(resource.getURI().path().substring(1))) - .findFirst(); - if (optionalResource.isPresent()) { - var contents = optionalResource.get().getContents(); - if (!contents.isEmpty()) { - treeItemIdsToExpand.add(treeItemId); - for (var rootObject : contents) { - var rootObjectId = this.identityService.getId(rootObject); - var rootObjectTreePathMaxDepth = 1; - rootObjectTreePathMaxDepth = this.addAllContents(editingContext, rootObjectId, rootObjectTreePathMaxDepth, treeItemIdsToExpand); - maxDepth = Math.max(maxDepth, rootObjectTreePathMaxDepth); - } - } + var contents = resource.getContents(); + if (!contents.isEmpty()) { + treeItemIdsToExpand.add(treeItemId); + for (var rootObject : contents) { + var rootObjectId = this.identityService.getId(rootObject); + var rootObjectTreePathMaxDepth = 1; + rootObjectTreePathMaxDepth = this.addAllContents(editingContext, rootObjectId, rootObjectTreePathMaxDepth, treeItemIdsToExpand, tree); + maxDepth = Math.max(maxDepth, rootObjectTreePathMaxDepth); } } } return new ExpandAllTreePathSuccessPayload(input.id(), new TreePath(treeItemIdsToExpand.stream().toList(), maxDepth)); } - private int addAllContents(IEditingContext editingContext, String treeItemId, int depth, Set treeItemIdsToExpand) { + private int addAllContents(IEditingContext editingContext, String treeItemId, int depth, Set treeItemIdsToExpand, Tree tree) { var depthConsidered = depth; - Optional optionalObject = this.objectSearchService.getObject(editingContext, treeItemId); - if (optionalObject.isPresent()) { - var contents = this.contentService.getContents(optionalObject.get()); + var object = this.getTreeItemObject(editingContext, treeItemId, tree); + + if (object instanceof EObject eObject) { + if (object instanceof Entity entity) { + // an Entity has a virtual node for its super types, this node should be a child of the Entity + var id = ExplorerDescriptionProvider.SETTING + this.identityService.getId(entity) + ExplorerDescriptionProvider.SETTING_ID_SEPARATOR + "superTypes"; + treeItemIdsToExpand.add(id); + var superTypes = entity.getSuperTypes(); + if (superTypes.size() > 0) { + depthConsidered = Math.max(depthConsidered, depth + 2); + } else { + depthConsidered = Math.max(depthConsidered, depth + 1); + } + } + var contents = this.contentService.getContents(eObject); if (!contents.isEmpty()) { treeItemIdsToExpand.add(treeItemId); @@ -113,7 +118,7 @@ private int addAllContents(IEditingContext editingContext, String treeItemId, in String childId = this.identityService.getId(child); treeItemIdsToExpand.add(childId); var childTreePathMaxDepth = depth + 1; - childTreePathMaxDepth = this.addAllContents(editingContext, childId, childTreePathMaxDepth, treeItemIdsToExpand); + childTreePathMaxDepth = this.addAllContents(editingContext, childId, childTreePathMaxDepth, treeItemIdsToExpand, tree); depthConsidered = Math.max(depthConsidered, childTreePathMaxDepth); } } else if (this.representationDataSearchService.existAnyRepresentationForTargetObjectId(treeItemId)) { @@ -124,4 +129,18 @@ private int addAllContents(IEditingContext editingContext, String treeItemId, in return depthConsidered; } + + private Object getTreeItemObject(IEditingContext editingContext, String treeItemId, Tree tree) { + var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + + if (optionalTreeDescription.isPresent()) { + var variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TreeDescription.ID, treeItemId); + return optionalTreeDescription.get().getTreeItemObjectProvider().apply(variableManager); + } + return null; + } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java index 7fe5d6a937..82dcccd813 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java @@ -13,16 +13,20 @@ package org.eclipse.sirius.web.application.views.explorer.services; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Objects; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature.Setting; +import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.sirius.components.core.RepresentationMetadata; import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.core.api.IObjectService; import org.eclipse.sirius.components.core.api.IRepresentationMetadataSearchService; +import org.eclipse.sirius.components.domain.Entity; import org.eclipse.sirius.components.representations.VariableManager; import org.eclipse.sirius.components.trees.renderer.TreeRenderer; import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerChildrenProvider; @@ -67,6 +71,15 @@ public boolean hasChildren(VariableManager variableManager) { String id = this.objectService.getId(eObject); hasChildren = this.representationDataSearchService.existAnyRepresentationForTargetObjectId(id); } + + if (!hasChildren && self instanceof Entity) { + hasChildren = true; + } + } else if (self instanceof Setting setting) { + var value = setting.get(true); + if (value instanceof Collection collection) { + hasChildren = !collection.isEmpty(); + } } return hasChildren; } @@ -117,8 +130,17 @@ private List getDefaultChildren(VariableManager variableManager) { representationMetadata.sort(Comparator.comparing(RepresentationMetadata::getLabel)); result.addAll(representationMetadata); List contents = this.objectService.getContents(self); + if (self instanceof Entity entity) { + result.add(((InternalEObject) entity).eSetting(entity.eClass().getEStructuralFeature("superTypes"))); + } result.addAll(contents); + } else if (self instanceof Setting setting) { + var value = setting.get(true); + if (value instanceof Collection collection) { + result.addAll(collection); + } } + } } return result; @@ -145,6 +167,8 @@ private String getTreeItemId(VariableManager variableManager) { id = resource.getURI().path().substring(1); } else if (self instanceof EObject) { id = this.objectService.getId(self); + } else if (self instanceof Setting setting) { + id = ExplorerDescriptionProvider.SETTING + this.objectService.getId(setting.getEObject()) + ExplorerDescriptionProvider.SETTING_ID_SEPARATOR + setting.getEStructuralFeature().getName(); } return id; } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java index a328d89c5a..f054f046f9 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java @@ -19,8 +19,12 @@ import java.util.Optional; import java.util.function.Predicate; +import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature.Setting; +import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.sirius.components.collaborative.api.IRepresentationImageProvider; import org.eclipse.sirius.components.core.CoreImageConstants; import org.eclipse.sirius.components.core.RepresentationMetadata; @@ -30,10 +34,13 @@ import org.eclipse.sirius.components.core.api.IURLParser; import org.eclipse.sirius.components.core.api.SemanticKindConstants; import org.eclipse.sirius.components.emf.ResourceMetadataAdapter; +import org.eclipse.sirius.components.emf.services.JSONResourceFactory; +import org.eclipse.sirius.components.emf.services.api.IEMFEditingContext; import org.eclipse.sirius.components.representations.Failure; import org.eclipse.sirius.components.representations.IRepresentationDescription; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.components.trees.renderer.TreeRenderer; @@ -59,6 +66,10 @@ public class ExplorerDescriptionProvider implements IEditingContextRepresentatio public static final String REPRESENTATION_NAME = "Explorer"; + public static final String SETTING = "setting:"; + + public static final String SETTING_ID_SEPARATOR = "::"; + private final IObjectService objectService; private final IURLParser urlParser; @@ -106,6 +117,7 @@ public List getRepresentationDescriptions(IEditingCo .canCreatePredicate(canCreatePredicate) .deleteHandler(this::getDeleteHandler) .renameHandler(this::getRenameHandler) + .treeItemObjectProvider(this::getTreeItemObject) .build(); return List.of(explorerTreeDescription); } @@ -142,6 +154,8 @@ private String getTreeItemId(VariableManager variableManager) { id = resource.getURI().path().substring(1); } else if (self instanceof EObject) { id = this.objectService.getId(self); + } else if (self instanceof Setting setting) { + id = SETTING + this.objectService.getId(setting.getEObject()) + SETTING_ID_SEPARATOR + setting.getEStructuralFeature().getName(); } return id; } @@ -153,6 +167,8 @@ private String getKind(VariableManager variableManager) { kind = representationMetadata.getKind(); } else if (self instanceof Resource) { kind = DOCUMENT_KIND; + } else if (self instanceof Setting) { + kind = "setting"; } else { kind = this.objectService.getKind(self); } @@ -173,6 +189,8 @@ private String getLabel(VariableManager variableManager) { var kind = this.objectService.getKind(self); label = this.urlParser.getParameterValues(kind).get(SemanticKindConstants.ENTITY_ARGUMENT).get(0); } + } else if (self instanceof Setting setting) { + label = setting.getEStructuralFeature().getName(); } return label; } @@ -229,7 +247,9 @@ private List getImageURL(VariableManager variableManager) { private IStatus getDeleteHandler(VariableManager variableManager) { var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); var optionalTreeItem = variableManager.get(TreeItem.SELECTED_TREE_ITEM, TreeItem.class); - if (optionalEditingContext.isPresent() && optionalTreeItem.isPresent()) { + var optionalTree = variableManager.get(TreeDescription.TREE, Tree.class); + + if (optionalEditingContext.isPresent() && optionalTreeItem.isPresent() && optionalTree.isPresent()) { IEditingContext editingContext = optionalEditingContext.get(); TreeItem treeItem = optionalTreeItem.get(); @@ -239,7 +259,7 @@ private IStatus getDeleteHandler(VariableManager variableManager) { if (optionalHandler.isPresent()) { IDeleteTreeItemHandler deleteTreeItemHandler = optionalHandler.get(); - return deleteTreeItemHandler.handle(editingContext, treeItem); + return deleteTreeItemHandler.handle(editingContext, treeItem, optionalTree.get()); } } return new Failure(""); @@ -248,7 +268,9 @@ private IStatus getDeleteHandler(VariableManager variableManager) { private IStatus getRenameHandler(VariableManager variableManager, String newLabel) { var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); var optionalTreeItem = variableManager.get(TreeItem.SELECTED_TREE_ITEM, TreeItem.class); - if (optionalEditingContext.isPresent() && optionalTreeItem.isPresent()) { + var optionalTree = variableManager.get(TreeDescription.TREE, Tree.class); + + if (optionalEditingContext.isPresent() && optionalTreeItem.isPresent() && optionalTree.isPresent()) { IEditingContext editingContext = optionalEditingContext.get(); TreeItem treeItem = optionalTreeItem.get(); @@ -258,9 +280,54 @@ private IStatus getRenameHandler(VariableManager variableManager, String newLabe if (optionalHandler.isPresent()) { IRenameTreeItemHandler renameTreeItemHandler = optionalHandler.get(); - return renameTreeItemHandler.handle(editingContext, treeItem, newLabel); + return renameTreeItemHandler.handle(editingContext, treeItem, newLabel, optionalTree.get()); } } return new Failure(""); } + + private Object getTreeItemObject(VariableManager variableManager) { + Object result = null; + var optionalTreeItemId = variableManager.get(TreeDescription.ID, String.class); + var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); + + if (optionalEditingContext.isPresent() && optionalTreeItemId.isPresent()) { + var treeItemId = optionalTreeItemId.get(); + var editingContext = optionalEditingContext.get(); + + if (treeItemId.startsWith(SETTING)) { + // the tree item is a setting, get the object and then the structural feature associated + var objectId = treeItemId.substring(SETTING.length(), treeItemId.indexOf(SETTING_ID_SEPARATOR)); + var featureName = treeItemId.substring(treeItemId.indexOf(SETTING_ID_SEPARATOR) + SETTING_ID_SEPARATOR.length()); + var optObject = this.objectService.getObject(editingContext, objectId); + if (optObject.isPresent()) { + InternalEObject internalObject = (InternalEObject) optObject.get(); + result = internalObject.eSetting(internalObject.eClass().getEStructuralFeature(featureName)); + } + } else { + var optionalObject = this.objectService.getObject(editingContext, treeItemId); + if (optionalObject.isPresent()) { + result = optionalObject.get(); + } else { + var optionalEditingDomain = Optional.of(editingContext) + .filter(IEMFEditingContext.class::isInstance) + .map(IEMFEditingContext.class::cast) + .map(IEMFEditingContext::getDomain); + + if (optionalEditingDomain.isPresent()) { + var editingDomain = optionalEditingDomain.get(); + ResourceSet resourceSet = editingDomain.getResourceSet(); + URI uri = new JSONResourceFactory().createResourceURI(treeItemId); + + result = resourceSet.getResources().stream() + .filter(resource -> resource.getURI().equals(uri)) + .findFirst() + .orElse(null); + } + } + } + } + + return result; + } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerNavigationService.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerNavigationService.java index 87cbd2f86e..a88cf28965 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerNavigationService.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerNavigationService.java @@ -21,7 +21,10 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.core.api.IIdentityService; -import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; +import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.web.application.UUIDParser; import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerNavigationService; import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.projections.RepresentationDataMetadataOnly; @@ -38,28 +41,28 @@ public class ExplorerNavigationService implements IExplorerNavigationService { private final IIdentityService identityService; - private final IObjectSearchService objectSearchService; - private final IRepresentationDataSearchService representationDataSearchService; - public ExplorerNavigationService(IIdentityService identityService, IObjectSearchService objectSearchService, IRepresentationDataSearchService representationDataSearchService) { + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + public ExplorerNavigationService(IIdentityService identityService, IRepresentationDataSearchService representationDataSearchService, IRepresentationDescriptionSearchService representationDescriptionSearchService) { this.identityService = Objects.requireNonNull(identityService); - this.objectSearchService = Objects.requireNonNull(objectSearchService); this.representationDataSearchService = Objects.requireNonNull(representationDataSearchService); + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); } @Override - public List getAncestors(IEditingContext editingContext, String treeItemId) { + public List getAncestors(IEditingContext editingContext, String treeItemId, Tree tree) { List ancestorsIds = new ArrayList<>(); var optionalRepresentationMetadata = new UUIDParser().parse(treeItemId).flatMap(this.representationDataSearchService::findMetadataById); - var optionalSemanticObject = this.objectSearchService.getObject(editingContext, treeItemId); + var optionalSemanticObject = this.getTreeItemObject(editingContext, treeItemId, tree); Optional optionalObject = Optional.empty(); if (optionalRepresentationMetadata.isPresent()) { // The first parent of a representation item is the item for its targetObject. optionalObject = optionalRepresentationMetadata.map(RepresentationDataMetadataOnly::targetObjectId) - .flatMap(objectId -> this.objectSearchService.getObject(editingContext, objectId)); + .flatMap(objectId -> this.getTreeItemObject(editingContext, objectId, tree)); } else if (optionalSemanticObject.isPresent()) { // The first parent of a semantic object item is the item for its actual container optionalObject = optionalSemanticObject.filter(EObject.class::isInstance) @@ -86,4 +89,18 @@ private String getItemId(Object object) { } return result; } + + private Optional getTreeItemObject(IEditingContext editingContext, String id, Tree tree) { + var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + + if (optionalTreeDescription.isPresent()) { + var variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TreeDescription.ID, id); + return Optional.ofNullable(optionalTreeDescription.get().getTreeItemObjectProvider().apply(variableManager)); + } + return Optional.empty(); + } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerTreePathProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerTreePathProvider.java index 4b0ecb212a..c811cc976a 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerTreePathProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerTreePathProvider.java @@ -51,7 +51,7 @@ public IPayload handle(IEditingContext editingContext, Tree tree, TreePathInput int maxDepth = 0; Set allAncestors = new LinkedHashSet<>(); for (String selectionEntryId : input.selectionEntryIds()) { - List itemAncestors = this.explorerNavigationService.getAncestors(editingContext, selectionEntryId); + List itemAncestors = this.explorerNavigationService.getAncestors(editingContext, selectionEntryId, tree); allAncestors.addAll(itemAncestors); maxDepth = Math.max(maxDepth, itemAncestors.size()); } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameDocumentTreeItemHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameDocumentTreeItemHandler.java index ac1135b4ee..42d289b447 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameDocumentTreeItemHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameDocumentTreeItemHandler.java @@ -12,22 +12,21 @@ *******************************************************************************/ package org.eclipse.sirius.web.application.views.explorer.services; -import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.Objects; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; import org.eclipse.sirius.components.emf.ResourceMetadataAdapter; -import org.eclipse.sirius.components.emf.services.JSONResourceFactory; -import org.eclipse.sirius.components.emf.services.api.IEMFEditingContext; import org.eclipse.sirius.components.representations.Failure; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; +import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.web.application.views.explorer.services.api.IRenameTreeItemHandler; import org.springframework.stereotype.Service; @@ -39,34 +38,41 @@ @Service public class RenameDocumentTreeItemHandler implements IRenameTreeItemHandler { + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + public RenameDocumentTreeItemHandler(IRepresentationDescriptionSearchService representationDescriptionSearchService) { + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); + } + @Override public boolean canHandle(IEditingContext editingContext, TreeItem treeItem, String newLabel) { return ExplorerDescriptionProvider.DOCUMENT_KIND.equals(treeItem.getKind()); } @Override - public IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel) { - var optionalEditingDomain = Optional.of(editingContext) - .filter(IEMFEditingContext.class::isInstance) - .map(IEMFEditingContext.class::cast) - .map(IEMFEditingContext::getDomain); + public IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel, Tree tree) { + IStatus result = new Failure("Something went wrong while handling this rename action."); + + var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); - if (optionalEditingDomain.isPresent()) { - var editingDomain = optionalEditingDomain.get(); - ResourceSet resourceSet = editingDomain.getResourceSet(); - URI uri = new JSONResourceFactory().createResourceURI(treeItem.getId()); + if (optionalTreeDescription.isPresent()) { + var variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TreeDescription.ID, treeItem.getId()); - List resourcesToRename = resourceSet.getResources().stream() - .filter(resource -> resource.getURI().equals(uri)) - .toList(); - resourcesToRename.forEach(resource -> resource.eAdapters().stream() - .filter(ResourceMetadataAdapter.class::isInstance) - .map(ResourceMetadataAdapter.class::cast) - .findFirst() - .ifPresent(adapter -> adapter.setName(newLabel))); + var object = optionalTreeDescription.get().getTreeItemObjectProvider().apply(variableManager); + if (object instanceof Resource resource) { + resource.eAdapters().stream() + .filter(ResourceMetadataAdapter.class::isInstance) + .map(ResourceMetadataAdapter.class::cast) + .findFirst() + .ifPresent(adapter -> adapter.setName(newLabel)); - return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + result = new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + } } - return new Failure("Something went wrong while handling this rename action."); + return result; } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameObjectTreeItemEventHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameObjectTreeItemEventHandler.java index bb5331a473..d0a64b8c85 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameObjectTreeItemEventHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameObjectTreeItemEventHandler.java @@ -19,11 +19,15 @@ import org.eclipse.sirius.components.core.api.IEditService; import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; import org.eclipse.sirius.components.core.api.SemanticKindConstants; import org.eclipse.sirius.components.representations.Failure; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; +import org.eclipse.sirius.components.trees.description.TreeDescription; import org.eclipse.sirius.web.application.views.explorer.services.api.IRenameTreeItemHandler; import org.springframework.stereotype.Service; @@ -39,9 +43,12 @@ public class RenameObjectTreeItemEventHandler implements IRenameTreeItemHandler private final IEditService editService; - public RenameObjectTreeItemEventHandler(IObjectService objectService, IEditService editService) { + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + public RenameObjectTreeItemEventHandler(IObjectService objectService, IEditService editService, IRepresentationDescriptionSearchService representationDescriptionSearchService) { this.objectService = Objects.requireNonNull(objectService); this.editService = Objects.requireNonNull(editService); + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); } @Override @@ -50,19 +57,28 @@ public boolean canHandle(IEditingContext editingContext, TreeItem treeItem, Stri } @Override - public IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel) { - var optionalObject = this.objectService.getObject(editingContext, treeItem.getId()); - if (optionalObject.isPresent()) { - Object object = optionalObject.get(); - var optionalLabelField = this.objectService.getLabelField(object); - if (optionalLabelField.isPresent()) { - String labelField = optionalLabelField.get(); - this.editService.editLabel(object, labelField, newLabel); - return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + public IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel, Tree tree) { + IStatus result = new Failure("Something went wrong while handling this rename action."); + + var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + + if (optionalTreeDescription.isPresent()) { + var variableManager = new VariableManager(); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + variableManager.put(TreeDescription.ID, treeItem.getId()); + + var object = optionalTreeDescription.get().getTreeItemObjectProvider().apply(variableManager); + if (object != null) { + var optionalLabelField = this.objectService.getLabelField(object); + if (optionalLabelField.isPresent()) { + String labelField = optionalLabelField.get(); + this.editService.editLabel(object, labelField, newLabel); + result = new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + } } } - - return new Failure("Something went wrong while handling this rename action."); + return result; } - } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameRepresentationTreeItemHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameRepresentationTreeItemHandler.java index e8d722dc40..083e447539 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameRepresentationTreeItemHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/RenameRepresentationTreeItemHandler.java @@ -21,6 +21,7 @@ import org.eclipse.sirius.components.representations.IRepresentation; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; import org.eclipse.sirius.web.application.views.explorer.services.api.IRenameTreeItemHandler; import org.springframework.stereotype.Service; @@ -39,7 +40,7 @@ public boolean canHandle(IEditingContext editingContext, TreeItem treeItem, Stri } @Override - public IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel) { + public IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel, Tree tree) { Map parameters = new HashMap<>(); parameters.put(EditingContextEventProcessor.REPRESENTATION_ID, treeItem.getId()); parameters.put(EditingContextEventProcessor.REPRESENTATION_LABEL, newLabel); diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IDeleteTreeItemHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IDeleteTreeItemHandler.java index ae6522f191..75caaded9e 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IDeleteTreeItemHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IDeleteTreeItemHandler.java @@ -14,6 +14,7 @@ import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; /** @@ -24,5 +25,5 @@ public interface IDeleteTreeItemHandler { boolean canHandle(IEditingContext editingContext, TreeItem treeItem); - IStatus handle(IEditingContext editingContext, TreeItem treeItem); + IStatus handle(IEditingContext editingContext, TreeItem treeItem, Tree tree); } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IExplorerNavigationService.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IExplorerNavigationService.java index ec1cd320c9..fab1aa6265 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IExplorerNavigationService.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IExplorerNavigationService.java @@ -15,6 +15,7 @@ import java.util.List; import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.trees.Tree; /** * Interface of the service for the navigation through the Sirius Web Explorer. @@ -23,7 +24,7 @@ */ public interface IExplorerNavigationService { - List getAncestors(IEditingContext editingContext, String treeItemId); + List getAncestors(IEditingContext editingContext, String treeItemId, Tree tree); /** * Implementation which does nothing, used for mocks in unit tests. @@ -33,7 +34,7 @@ public interface IExplorerNavigationService { class NoOp implements IExplorerNavigationService { @Override - public List getAncestors(IEditingContext editingContext, String treeItemId) { + public List getAncestors(IEditingContext editingContext, String treeItemId, Tree tree) { return List.of(); } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IRenameTreeItemHandler.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IRenameTreeItemHandler.java index cc208df90e..bf344ca767 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IRenameTreeItemHandler.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/api/IRenameTreeItemHandler.java @@ -14,6 +14,7 @@ import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.TreeItem; /** @@ -24,5 +25,5 @@ public interface IRenameTreeItemHandler { boolean canHandle(IEditingContext editingContext, TreeItem treeItem, String newLabel); - IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel); + IStatus handle(IEditingContext editingContext, TreeItem treeItem, String newLabel, Tree tree); } \ No newline at end of file diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java new file mode 100644 index 0000000000..70f780ed8e --- /dev/null +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2024 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.sirius.web.application.controllers.trees; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import com.jayway.jsonpath.JsonPath; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.eclipse.sirius.components.collaborative.trees.dto.TreeEventInput; +import org.eclipse.sirius.components.collaborative.trees.dto.TreeRefreshedEventPayload; +import org.eclipse.sirius.components.trees.Tree; +import org.eclipse.sirius.components.trees.TreeItem; +import org.eclipse.sirius.components.trees.tests.graphql.ExpandAllTreePathQueryRunner; +import org.eclipse.sirius.components.trees.tests.graphql.TreeEventSubscriptionRunner; +import org.eclipse.sirius.web.AbstractIntegrationTests; +import org.eclipse.sirius.web.application.views.explorer.services.ExplorerDescriptionProvider; +import org.eclipse.sirius.web.data.StudioIdentifiers; +import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlConfig; +import org.springframework.transaction.annotation.Transactional; + +import graphql.execution.DataFetcherResult; +import reactor.test.StepVerifier; + +/** + * Integration tests of a non semantic element in the explorer. + * + * @author Jerome Gout + */ +@Transactional +@SuppressWarnings("checkstyle:MultipleStringLiterals") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ExplorerNonSemanticElementControllerTests extends AbstractIntegrationTests { + + @Autowired + private IGivenInitialServerState givenInitialServerState; + + @Autowired + private TreeEventSubscriptionRunner treeEventSubscriptionRunner; + + @Autowired + private ExpandAllTreePathQueryRunner expandAllTreePathQueryRunner; + + @BeforeEach + public void beforeEach() { + this.givenInitialServerState.initialize(); + } + + @Test + @DisplayName("Given a sample studio, when we expand all the domain elements, then underneath entities have a superTypes child") + @Sql(scripts = {"/scripts/studio.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = {"/scripts/cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED)) + public void givenStudioWhenWeAskForTheTreePathOfPapayaViewObjectThenItsPathInTheExplorerIsReturned() { + var input = new TreeEventInput(UUID.randomUUID(), StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), ExplorerDescriptionProvider.PREFIX, List.of(), List.of()); + var flux = this.treeEventSubscriptionRunner.run(input); + + var treeId = new AtomicReference(); + var domainDocumentId = new AtomicReference(); + + Consumer initialTreeContentConsumer = this.getTreeSubscriptionConsumer(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getChildren()).hasSize(5); + assertThat(tree.getChildren()).allSatisfy(treeItem -> assertThat(treeItem.getChildren()).isEmpty()); + + treeId.set(tree.getId()); + domainDocumentId.set(tree.getChildren().get(1).getId()); // Domain document is the second child of the tree + }); + + // Expand the part of the tree corresponding to the Domain document + var treeItemIds = new AtomicReference>(); + + Runnable getTreePath = () -> { + Map variables = Map.of( + "editingContextId", StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), + "treeId", treeId.get(), + "treeItemId", domainDocumentId.get() + ); + var result = this.expandAllTreePathQueryRunner.run(variables); + List treeItemIdsToExpand = JsonPath.read(result, "$.data.viewer.editingContext.expandAllTreePath.treeItemIdsToExpand"); + assertThat(treeItemIdsToExpand).isNotEmpty(); + // there are 3 entities in the Domain document, so should get 3 superType treeItems + assertThat(treeItemIdsToExpand.stream() + .filter(id -> id.startsWith(ExplorerDescriptionProvider.SETTING)) + .toList() + ).hasSize(3); + treeItemIds.set(treeItemIdsToExpand); + }; + + StepVerifier.create(flux) + .consumeNextWith(initialTreeContentConsumer) + .then(getTreePath) + .thenCancel() + .verify(Duration.ofSeconds(10)); + + + var expandedTreeInput = new TreeEventInput(UUID.randomUUID(), StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), ExplorerDescriptionProvider.PREFIX, treeItemIds.get(), List.of()); + var expandedTreeFlux = this.treeEventSubscriptionRunner.run(expandedTreeInput); + + Consumer initialExpandedTreeContentConsumer = this.getTreeSubscriptionConsumer(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getChildren()).isNotEmpty(); + assertThat(tree.getChildren()).hasSize(5); + var domainDocument = tree.getChildren().get(1); + assertThat(domainDocument).isNotNull(); + assertThat(domainDocument.getChildren()).isNotEmpty(); + assertThat(domainDocument.getChildren()).hasSize(1); + assertThat(domainDocument.getChildren().get(0)).isNotNull(); + List domainElements = domainDocument.getChildren().get(0).getChildren(); + assertThat(domainElements).hasSize(3); + assertThat(domainElements.get(0).getLabel()).isEqualTo("Root"); + assertThat(domainElements.get(0).getChildren()).isNotEmpty(); + assertThat(domainElements.get(0).getChildren()).hasSize(3); + assertThat(domainElements.get(0).getChildren().get(0).getLabel()).isEqualTo("superTypes"); + }); + + StepVerifier.create(expandedTreeFlux) + .consumeNextWith(initialExpandedTreeContentConsumer) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + + private Consumer getTreeSubscriptionConsumer(Consumer treeConsumer) { + return object -> Optional.of(object) + .filter(DataFetcherResult.class::isInstance) + .map(DataFetcherResult.class::cast) + .map(DataFetcherResult::getData) + .filter(TreeRefreshedEventPayload.class::isInstance) + .map(TreeRefreshedEventPayload.class::cast) + .map(TreeRefreshedEventPayload::tree) + .ifPresentOrElse(treeConsumer, () -> fail("Missing tree")); + } +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/DeleteTreeItemEventHandler.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/DeleteTreeItemEventHandler.java index 2d32f97458..b3bfa177c9 100644 --- a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/DeleteTreeItemEventHandler.java +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/DeleteTreeItemEventHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2023 Obeo. + * Copyright (c) 2021, 2024 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 @@ -87,6 +87,7 @@ public void handle(One payloadSink, Many changeDesc VariableManager variableManager = new VariableManager(); variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); variableManager.put(TreeItem.SELECTED_TREE_ITEM, treeItem); + variableManager.put(TreeDescription.TREE, tree); var status = treeDescription.getDeleteHandler().apply(variableManager); if (status instanceof Success success) { diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/RenameTreeItemEventHandler.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/RenameTreeItemEventHandler.java index a21ee8f254..0356e2c09a 100644 --- a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/RenameTreeItemEventHandler.java +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/RenameTreeItemEventHandler.java @@ -88,6 +88,7 @@ public void handle(One payloadSink, Many changeDesc VariableManager variableManager = new VariableManager(); variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); variableManager.put(TreeItem.SELECTED_TREE_ITEM, treeItem); + variableManager.put(TreeDescription.TREE, tree); var status = treeDescription.getRenameHandler().apply(variableManager, input.newLabel()); if (status instanceof Success success) { diff --git a/packages/trees/backend/sirius-components-trees/src/main/java/org/eclipse/sirius/components/trees/description/TreeDescription.java b/packages/trees/backend/sirius-components-trees/src/main/java/org/eclipse/sirius/components/trees/description/TreeDescription.java index bc435ab8fb..6a8c4e634e 100644 --- a/packages/trees/backend/sirius-components-trees/src/main/java/org/eclipse/sirius/components/trees/description/TreeDescription.java +++ b/packages/trees/backend/sirius-components-trees/src/main/java/org/eclipse/sirius/components/trees/description/TreeDescription.java @@ -32,6 +32,16 @@ @Immutable public final class TreeDescription implements IRepresentationDescription { + /** + * The variable name used for the id. + */ + public static final String ID = "id"; + + /** + * The variable name used to store a reference to a tree. + */ + public static final String TREE = "tree"; + private String id; private String label; @@ -66,6 +76,8 @@ public final class TreeDescription implements IRepresentationDescription { private BiFunction renameHandler; + private Function treeItemObjectProvider; + private TreeDescription() { // Prevent instantiation } @@ -145,6 +157,10 @@ public BiFunction getRenameHandler() { return this.renameHandler; } + public Function getTreeItemObjectProvider() { + return this.treeItemObjectProvider; + } + @Override public String toString() { String pattern = "{0} '{'id: {1}, label: {2}'}'"; @@ -193,6 +209,8 @@ public static final class Builder { private BiFunction renameHandler; + private Function treeItemObjectProvider; + private Builder(String id) { this.id = Objects.requireNonNull(id); } @@ -277,6 +295,11 @@ public Builder renameHandler(BiFunction rename return this; } + public Builder treeItemObjectProvider(Function treeItemObjectProvider) { + this.treeItemObjectProvider = Objects.requireNonNull(treeItemObjectProvider); + return this; + } + public TreeDescription build() { TreeDescription treeDescription = new TreeDescription(); treeDescription.id = Objects.requireNonNull(this.id); @@ -296,6 +319,7 @@ public TreeDescription build() { treeDescription.canCreatePredicate = Objects.requireNonNull(this.canCreatePredicate); treeDescription.deleteHandler = Objects.requireNonNull(this.deleteHandler); treeDescription.renameHandler = Objects.requireNonNull(this.renameHandler); + treeDescription.treeItemObjectProvider = Objects.requireNonNull(this.treeItemObjectProvider); return treeDescription; } }