Skip to content

Commit

Permalink
[3763] Fix expand issues with the SelectionDialog tree
Browse files Browse the repository at this point in the history
Bug: #3763
Signed-off-by: Florian Barbin <[email protected]>
  • Loading branch information
florianbarbin committed Aug 28, 2024
1 parent 85d9a27 commit 8b89d56
Show file tree
Hide file tree
Showing 9 changed files with 436 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ As a result, the following maven modules have been deleted: `sirius-web-sample-a
- https://github.com/eclipse-sirius/sirius-web/issues/3763[#3763] [core] updates some services behavior:
** The `org.eclipse.sirius.components.emf.services.DefaultIdentityService#getId(Object object)` Can now provides the Id if the Object is of type `org.eclipse.emf.ecore.resource.Resource`. Before this change, it would have returned null.
** The `org.eclipse.sirius.components.emf.services.DefaultLabelService` Can now provides the label if the Object is of type `org.eclipse.emf.ecore.resource.Resource`. Before this change, it would have returned an empty string.
** The `org.eclipse.sirius.components.emf.services.DefaultContentService#getContents(Object)` Can now provides the content if the Object is of type `org.eclipse.emf.ecore.resource.Resource`. Before this change, it would have returned an empty list.


=== Dependency update
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
*******************************************************************************/
package org.eclipse.sirius.components.emf.services;

import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
import org.eclipse.sirius.components.core.api.IDefaultContentService;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.springframework.stereotype.Service;

/**
* Default implementation of {@link IDefaultContentService}.
Expand All @@ -48,6 +48,10 @@ public List<Object> getContents(Object object) {
contents.addAll(eObject.eContents());
}
}
else if (object instanceof Resource resource) {
// The object may be a document
contents.addAll(resource.getContents());
}
return contents;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sirius</groupId>
<artifactId>
sirius-components-collaborative-trees
</artifactId>
<version>2024.7.10</version>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*******************************************************************************
* 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.components.collaborative.selection.services;

import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;

import org.eclipse.sirius.components.collaborative.selection.services.api.ISelectionDialogNavigationService;
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.IPayload;
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.springframework.stereotype.Service;

/**
* Implementation of {@link IExpandAllTreePathProvider} for the Selection Dialog Tree.
*
* @author frouene
* @author fbarbin
*/
@Service
public class SelectionDialogExpandAllTreePathProvider implements IExpandAllTreePathProvider {

private final IIdentityService identityService;

private final IContentService contentService;

private final ISelectionDialogNavigationService selectionDialogNavigationService;

private final IRepresentationDescriptionSearchService representationDescriptionSearchService;

public SelectionDialogExpandAllTreePathProvider(IIdentityService identityService, IContentService contentService, ISelectionDialogNavigationService selectionDialogNavigationService, IRepresentationDescriptionSearchService representationDescriptionSearchService) {
this.identityService = Objects.requireNonNull(identityService);
this.contentService = Objects.requireNonNull(contentService);
this.selectionDialogNavigationService = Objects.requireNonNull(selectionDialogNavigationService);
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
}

@Override
public boolean canHandle(Tree tree) {
return tree.getDescriptionId().startsWith(ISelectionDialogNavigationService.SELECTION_DIALOG_TREE_DESCRIPTION_KIND);
}

@Override
public IPayload handle(IEditingContext editingContext, Tree tree, ExpandAllTreePathInput input) {
int maxDepth = 0;
String treeItemId = input.treeItemId();
Set<String> treeItemIdsToExpand = new LinkedHashSet<>();
var object = this.getTreeItemObject(editingContext, treeItemId, tree);
if (object != null) {
// We need to get the current depth of the tree item
var itemAncestors = this.selectionDialogNavigationService.getAncestors(editingContext, treeItemId, tree);
maxDepth = itemAncestors.size();
maxDepth = this.addAllContents(editingContext, treeItemId, maxDepth, treeItemIdsToExpand, tree);
}
return new ExpandAllTreePathSuccessPayload(input.id(), new TreePath(treeItemIdsToExpand.stream().toList(), maxDepth));
}

private int addAllContents(IEditingContext editingContext, String treeItemId, int depth, Set<String> treeItemIdsToExpand, Tree tree) {
var depthConsidered = depth;
var object = this.getTreeItemObject(editingContext, treeItemId, tree);
if (object != null) {
var contents = this.contentService.getContents(object);
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, tree);
depthConsidered = Math.max(depthConsidered, childTreePathMaxDepth);
}
}
}

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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*******************************************************************************
* 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.components.collaborative.selection.services;

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

import org.eclipse.sirius.components.collaborative.selection.services.api.ISelectionDialogNavigationService;
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.representations.VariableManager;
import org.eclipse.sirius.components.trees.Tree;
import org.eclipse.sirius.components.trees.description.TreeDescription;
import org.springframework.stereotype.Service;

/**
* Services for the navigation through the Selection Dialog Tree.
*
* @author frouene
* @author fbarbin
*/
@Service
public class SelectionDialogNavigationService implements ISelectionDialogNavigationService {

private final IObjectService objectService;

private final IRepresentationDescriptionSearchService representationDescriptionSearchService;

public SelectionDialogNavigationService(IObjectService objectService, IRepresentationDescriptionSearchService representationDescriptionSearchService) {
this.objectService = Objects.requireNonNull(objectService);
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
}

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

Optional<Object> optionalObject = this.getParentSemanticObject(treeItemId, ancestorsIds, editingContext, tree);
while (optionalObject.isPresent()) {
String parentId = this.objectService.getId(optionalObject.get());
ancestorsIds.add(parentId);
optionalObject = this.getParentSemanticObject(parentId, ancestorsIds, editingContext, tree);
}
return ancestorsIds;
}

private Optional<Object> getParentSemanticObject(String elementId, List<String> ancestorsIds, IEditingContext editingContext, Tree tree) {
Optional<Object> result = Optional.empty();

var variableManager = new VariableManager();
var optionalSemanticObject = this.getTreeItemObject(editingContext, elementId, tree);
var optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId())
.filter(TreeDescription.class::isInstance)
.map(TreeDescription.class::cast);

if (optionalSemanticObject.isPresent() && optionalTreeDescription.isPresent()) {
variableManager.put(VariableManager.SELF, optionalSemanticObject.get());
variableManager.put(TreeDescription.ID, elementId);
variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext);
result = Optional.ofNullable(optionalTreeDescription.get().getParentObjectProvider().apply(variableManager));
}
return result;
}

private Optional<Object> 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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*******************************************************************************
* Copyright (c) 2023, 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.components.collaborative.selection.services;

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

import org.eclipse.sirius.components.collaborative.selection.services.api.ISelectionDialogNavigationService;
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.springframework.stereotype.Service;

/**
* ITreePathProvider implementation for the Selection Dialog tree.
*
* @author pcdavid
* @author fbarbin
*/
@Service
public class SelectionDialogTreePathProvider implements ITreePathProvider {

private final ISelectionDialogNavigationService selectionDialogNavigationService;

public SelectionDialogTreePathProvider(ISelectionDialogNavigationService selectionDialogNavigationService) {
this.selectionDialogNavigationService = Objects.requireNonNull(selectionDialogNavigationService);
}

@Override
public boolean canHandle(Tree tree) {
return tree != null && tree.getDescriptionId().startsWith(ISelectionDialogNavigationService.SELECTION_DIALOG_TREE_DESCRIPTION_KIND);
}

@Override
public IPayload handle(IEditingContext editingContext, Tree tree, TreePathInput input) {
int maxDepth = 0;
Set<String> allAncestors = new LinkedHashSet<>();
for (String selectionEntryId : input.selectionEntryIds()) {
List<String> itemAncestors = this.selectionDialogNavigationService.getAncestors(editingContext, selectionEntryId, tree);
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,44 @@
/*******************************************************************************
* 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.components.collaborative.selection.services.api;

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 Selection Dialog Tree.
*
* @author fbarbin
*/
public interface ISelectionDialogNavigationService {

String SELECTION_DIALOG_TREE_DESCRIPTION_KIND = "siriusComponents://selectionDialogTreeDescription";

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

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

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ export const SelectionDialog = ({
enableMultiSelection={true}
synchronizedWithSelection={true}
activeFilterIds={[]}
textToFilter={null}
textToHighlight={null}
textToFilter={''}
textToHighlight={''}
treeItemActionRender={(props) => <SelectionDialogTreeItemAction {...props} />}
/>
);
Expand Down
Loading

0 comments on commit 8b89d56

Please sign in to comment.