Skip to content

Commit

Permalink
Fix delete by using the model server
Browse files Browse the repository at this point in the history
- Use ModelServer to delegate GLSP delete
- Sort commands by descending index before sending to model server
- Add support to tree for compoundcommands
- Create correct compoundcommand on tree

Fixes eclipse-emfcloud#180
  • Loading branch information
eneufeld committed Nov 5, 2020
1 parent 2b21bea commit 1a09f23
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,96 @@
******************************************************************************/
package com.eclipsesource.workflow.glsp.server.handler.operation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emfcloud.modelserver.coffee.model.coffee.Flow;
import org.eclipse.emfcloud.modelserver.coffee.model.coffee.Node;
import org.eclipse.glsp.api.model.GraphicalModelState;
import org.eclipse.glsp.api.operation.kind.DeleteOperation;
import org.eclipse.glsp.graph.GEdge;
import org.eclipse.glsp.graph.GModelElement;
import org.eclipse.glsp.graph.GNode;
import org.eclipse.glsp.server.operationhandler.BasicOperationHandler;

import com.eclipsesource.workflow.glsp.server.model.WorkflowModelServerAccess;
import com.eclipsesource.workflow.glsp.server.model.WorkflowModelState;
import com.eclipsesource.workflow.glsp.server.wfnotation.DiagramElement;
import com.eclipsesource.workflow.glsp.server.wfnotation.Shape;

public class DeleteOperationHandler extends BasicOperationHandler<DeleteOperation> {
public class DeleteOperationHandler extends ModelServerAwareBasicOperationHandler<DeleteOperation> {

private Set<EObject> toDelete;
private Set<EObject> toDeleteNodes;
private Set<EObject> toDeleteEdges;
private Set<DiagramElement> toDeleteLocal;

@Override
public void executeOperation(DeleteOperation operation, GraphicalModelState modelState) {
toDelete = new HashSet<>();
public void executeOperation(DeleteOperation operation, GraphicalModelState modelState,
WorkflowModelServerAccess modelAccess) throws Exception {
toDeleteNodes = new HashSet<>();
toDeleteEdges = new HashSet<>();
toDeleteLocal = new HashSet<>();
operation.getElementIds().forEach(id -> collectElementsToDelete(id, modelState));
toDelete.forEach(e -> EcoreUtil.delete(e, true));
toDeleteLocal.forEach(e -> EcoreUtil.delete(e, true));

List<Command> deleteEdges = delete(toDeleteEdges, modelAccess);
List<Command> deleteNodes = delete(toDeleteNodes, modelAccess);
List<Command> unifiedToDelete = new ArrayList<>();
Comparator<Command> sortByIndex = new Comparator<Command>() {

@Override
public int compare(Command o1, Command o2) {
if (!(o1 instanceof RemoveCommand))
return 1;
if (!(o2 instanceof RemoveCommand))
return -1;
RemoveCommand rc1 = (RemoveCommand) o1;
RemoveCommand rc2 = (RemoveCommand) o2;
CommandParameter.Indices cp2 = (CommandParameter.Indices) rc2.getCollection().iterator().next();
CommandParameter.Indices cp1 = (CommandParameter.Indices) rc1.getCollection().iterator().next();
return cp2.getIndices()[0] - cp1.getIndices()[0];

}
};
// need to sort as otherwise the index is not correct when commands are applied.
Collections.sort(deleteEdges, sortByIndex);
Collections.sort(deleteNodes, sortByIndex);
unifiedToDelete.addAll(deleteEdges);
unifiedToDelete.addAll(deleteNodes);

CompoundCommand cc = new CompoundCommand(unifiedToDelete);
if (!modelAccess.edit(cc).thenApply(res -> res.body()).get()) {
throw new IllegalAccessError("Could not execute command: " + cc);
}
}

@SuppressWarnings("unchecked")
private List<Command> delete(Set<EObject> eObjects, final WorkflowModelServerAccess modelAccess) {
List<Command> result = new ArrayList<>();
for (EObject e : eObjects) {
EObject container = e.eContainer();
EStructuralFeature containingFeature = e.eContainingFeature();
// use index as object id cannot be used due to glsp -> modelserver -> glsp
// communication
int index = ((EList<EObject>) container.eGet(containingFeature)).indexOf(e);
Command removeEdgesCommand = RemoveCommand.create(modelAccess.getEditingDomain(), container,
containingFeature, index);
result.add(removeEdgesCommand);

}
return result;
}

protected void collectElementsToDelete(String id, GraphicalModelState modelState) {
Expand All @@ -55,11 +116,11 @@ protected void collectElementsToDelete(String id, GraphicalModelState modelState
WorkflowModelServerAccess modelAccess = WorkflowModelState.getModelAccess(modelState);
if (element instanceof GNode) {
Node node = modelAccess.getNodeById(element.getId());
toDelete.add(node);
toDeleteNodes.add(node);

Optional<DiagramElement> diagramElement = modelAccess.getWorkflowFacade().findDiagramElement(node);
if (!diagramElement.isEmpty() && diagramElement.get() instanceof Shape) {
toDelete.add(diagramElement.get());
toDeleteLocal.add(diagramElement.get());
}

modelState.getIndex().getIncomingEdges(element)
Expand All @@ -74,14 +135,14 @@ protected void collectElementsToDelete(String id, GraphicalModelState modelState
if (maybeFlow.isEmpty()) {
return;
}
toDelete.add(maybeFlow.get());
toDeleteEdges.add(maybeFlow.get());

Optional<DiagramElement> edge = maybeFlow
.flatMap(flow -> modelAccess.getWorkflowFacade().findDiagramElement(flow));
if (edge.isEmpty()) {
return;
}
toDelete.add(edge.get());
toDeleteLocal.add(edge.get());
}
}

Expand Down
Loading

0 comments on commit 1a09f23

Please sign in to comment.