Skip to content

Commit

Permalink
[3628] Restore support for expand all and reveal in the explorer
Browse files Browse the repository at this point in the history
Bug: #3628
Signed-off-by: Stéphane Bégaudeau <[email protected]>
  • Loading branch information
sbegaudeau committed Jun 14, 2024
1 parent c382016 commit 7b351a0
Show file tree
Hide file tree
Showing 11 changed files with 862 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ More existing APIs will be migrated to this new common pattern.
- https://github.com/eclipse-sirius/sirius-web/issues/3575[#3575] [core] Restore support for studio palette colors
- https://github.com/eclipse-sirius/sirius-web/issues/3582[#3582] [tree] Restore the initial direct edit tree item label for the explorer
- https://github.com/eclipse-sirius/sirius-web/issues/3611[#3611] [diagram] Fix missing creation tool image in the contextual palette
- https://github.com/eclipse-sirius/sirius-web/issues/3628[#3628] [sirius-web] Restore support for expand all and reveal in the explorer

=== New Features

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private GroupDescription getGroupDescription() {
EcorePackage.Literals.ELONG_OBJECT,
EcorePackage.Literals.ESHORT,
EcorePackage.Literals.ESHORT_OBJECT
);
);

for (var dataType : numericDataTypes) {
ifDescriptions.add(new NumberIfDescriptionProvider(dataType, this.composedAdapterFactory, this.propertiesValidationProvider, this.emfMessageService, this.semanticTargetIdProvider).getIfDescription());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*******************************************************************************
* 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.views.explorer.services;

import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

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;
import org.eclipse.sirius.components.collaborative.trees.dto.TreePath;
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.trees.Tree;
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;

/**
* Implementation of {@link IExpandAllTreePathProvider} for Sirius Web Tree.
*
* @author arichard
*/
@Service
public class ExpandAllTreePathProvider implements IExpandAllTreePathProvider {

private final IObjectSearchService objectSearchService;

private final IIdentityService identityService;

private final IContentService contentService;

private final IExplorerNavigationService explorerNavigationService;

private final IRepresentationDataSearchService representationDataSearchService;

public ExpandAllTreePathProvider(IObjectSearchService objectSearchService, IIdentityService identityService, IContentService contentService, IExplorerNavigationService explorerNavigationService, IRepresentationDataSearchService representationDataSearchService) {
this.objectSearchService = Objects.requireNonNull(objectSearchService);
this.identityService = Objects.requireNonNull(identityService);
this.contentService = Objects.requireNonNull(contentService);
this.explorerNavigationService = Objects.requireNonNull(explorerNavigationService);
this.representationDataSearchService = Objects.requireNonNull(representationDataSearchService);
}

@Override
public boolean canHandle(Tree tree) {
return tree.getDescriptionId().equals(ExplorerDescriptionProvider.DESCRIPTION_ID);
}

@Override
public IPayload handle(IEditingContext editingContext, Tree tree, ExpandAllTreePathInput input) {
int maxDepth = 0;
String treeItemId = input.treeItemId();
Set<String> treeItemIdsToExpand = new HashSet<>();
var object = this.objectSearchService.getObject(editingContext, treeItemId);
if (object.isPresent()) {
// We need to get the current depth of the tree item
var itemAncestors = this.explorerNavigationService.getAncestors(editingContext, treeItemId);
maxDepth = itemAncestors.size();
maxDepth = this.addAllContents(editingContext, treeItemId, maxDepth, treeItemIdsToExpand);
} else {
// 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);
}
}
}
}
}
return new ExpandAllTreePathSuccessPayload(input.id(), new TreePath(treeItemIdsToExpand.stream().toList(), maxDepth));
}

private int addAllContents(IEditingContext editingContext, String treeItemId, int depth, Set<String> treeItemIdsToExpand) {
var depthConsidered = depth;
Optional<Object> optionalObject = this.objectSearchService.getObject(editingContext, treeItemId);
if (optionalObject.isPresent()) {
var contents = this.contentService.getContents(optionalObject.get());
if (!contents.isEmpty()) {
treeItemIdsToExpand.add(treeItemId);

for (var child : contents) {
String childId = this.identityService.getId(child);
treeItemIdsToExpand.add(childId);
var childTreePathMaxDepth = depth + 1;
childTreePathMaxDepth = this.addAllContents(editingContext, childId, childTreePathMaxDepth, treeItemIdsToExpand);
depthConsidered = Math.max(depthConsidered, childTreePathMaxDepth);
}
} else if (this.representationDataSearchService.existAnyRepresentationForTargetObjectId(treeItemId)) {
treeItemIdsToExpand.add(treeItemId);
depthConsidered = Math.max(depthConsidered, depth + 1);
}
}

return depthConsidered;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*******************************************************************************
* 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.views.explorer.services;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.eclipse.emf.ecore.EObject;
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.web.application.UUIDParser;
import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerNavigationService;
import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.RepresentationData;
import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.services.api.IRepresentationDataSearchService;
import org.springframework.stereotype.Service;

/**
* Services for the navigation through the Sirius Web Explorer.
*
* @author arichard
*/
@Service
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) {
this.identityService = Objects.requireNonNull(identityService);
this.objectSearchService = Objects.requireNonNull(objectSearchService);
this.representationDataSearchService = Objects.requireNonNull(representationDataSearchService);
}

@Override
public List<String> getAncestors(IEditingContext editingContext, String treeItemId) {
List<String> ancestorsIds = new ArrayList<>();

var optionalRepresentation = new UUIDParser().parse(treeItemId).flatMap(this.representationDataSearchService::findById);
var optionalSemanticObject = this.objectSearchService.getObject(editingContext, treeItemId);

Optional<Object> optionalObject = Optional.empty();
if (optionalRepresentation.isPresent()) {
// The first parent of a representation item is the item for its targetObject.
optionalObject = optionalRepresentation.map(RepresentationData::getTargetObjectId)
.flatMap(objectId -> this.objectSearchService.getObject(editingContext, objectId));
} 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)
.map(EObject.class::cast)
.map(eObject -> Optional.<Object> ofNullable(eObject.eContainer()).orElse(eObject.eResource()));
}

while (optionalObject.isPresent()) {
ancestorsIds.add(this.getItemId(optionalObject.get()));
optionalObject = optionalObject
.filter(EObject.class::isInstance)
.map(EObject.class::cast)
.map(eObject -> Optional.<Object>ofNullable(eObject.eContainer()).orElse(eObject.eResource()));
}
return ancestorsIds;
}

private String getItemId(Object object) {
String result = null;
if (object instanceof Resource resource) {
result = resource.getURI().path().substring(1);
} else if (object instanceof EObject) {
result = this.identityService.getId(object);
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*******************************************************************************
* 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.views.explorer.services;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.eclipse.sirius.components.collaborative.trees.api.ITreePathProvider;
import org.eclipse.sirius.components.collaborative.trees.dto.TreePath;
import org.eclipse.sirius.components.collaborative.trees.dto.TreePathInput;
import org.eclipse.sirius.components.collaborative.trees.dto.TreePathSuccessPayload;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.trees.Tree;
import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerNavigationService;
import org.springframework.stereotype.Service;

/**
* Implementation of {@link ITreePathProvider} for the Sirius Web Explorer.
*
* @author pcdavid
*/
@Service
public class ExplorerTreePathProvider implements ITreePathProvider {

private final IExplorerNavigationService explorerNavigationService;

public ExplorerTreePathProvider(IExplorerNavigationService explorerNavigationService) {
this.explorerNavigationService = Objects.requireNonNull(explorerNavigationService);
}

@Override
public boolean canHandle(Tree tree) {
return tree.getDescriptionId().equals(ExplorerDescriptionProvider.DESCRIPTION_ID);
}

@Override
public IPayload handle(IEditingContext editingContext, Tree tree, TreePathInput input) {
int maxDepth = 0;
Set<String> allAncestors = new HashSet<>();
for (String selectionEntryId : input.selectionEntryIds()) {
List<String> itemAncestors = this.explorerNavigationService.getAncestors(editingContext, selectionEntryId);
allAncestors.addAll(itemAncestors);
maxDepth = Math.max(maxDepth, itemAncestors.size());
}
return new TreePathSuccessPayload(input.id(), new TreePath(allAncestors.stream().toList(), maxDepth));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*******************************************************************************
* 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.views.explorer.services.api;

import java.util.List;

import org.eclipse.sirius.components.core.api.IEditingContext;

/**
* Interface of the service for the navigation through the Sirius Web Explorer.
*
* @author arichard
*/
public interface IExplorerNavigationService {

List<String> getAncestors(IEditingContext editingContext, String treeItemId);

/**
* Implementation which does nothing, used for mocks in unit tests.
*
* @author frouene
*/
class NoOp implements IExplorerNavigationService {

@Override
public List<String> getAncestors(IEditingContext editingContext, String treeItemId) {
return List.of();
}
}

}
Loading

0 comments on commit 7b351a0

Please sign in to comment.