blob: aec813eb1683896603d2d4c40b89213c7eaf65de [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2019 Mia-Software and others.
* All rights reserved. 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
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Nicolas Bros (Mia-Software) - initial API and implementation
*******************************************************************************/
package org.eclipse.modisco.infra.browser.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.command.IdentityCommand;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.CopyCommand;
import org.eclipse.emf.edit.command.DragAndDropCommand;
import org.eclipse.emf.edit.command.MoveCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.modisco.infra.browser.uicore.internal.model.ITreeElement;
import org.eclipse.modisco.infra.browser.uicore.internal.model.LinkItem;
import org.eclipse.modisco.infra.browser.uicore.internal.model.ModelElementItem;
/** Handles drag&drop on a {@link ModelElementItem} */
public class DragAndDropOnModelElementCommand extends DragAndDropCommand {
private final ModelElementItemEx modelElementItem;
public DragAndDropOnModelElementCommand(final EditingDomain editingDomain,
final ModelElementItemEx modelElementItem, final float location, final int operations,
final int operation, final Collection<?> collection) {
super(editingDomain, modelElementItem, location, operations, operation, collection);
this.modelElementItem = modelElementItem;
}
public ModelElementItem getModelElementItem() {
return this.modelElementItem;
}
public Command getDropCommand() {
return this.dropCommand;
}
@Override
protected Object getParent(final Object object) {
if (object instanceof ITreeElement) {
ITreeElement treeElement = (ITreeElement) object;
return treeElement.getTreeParent();
}
return Collections.emptyList();
}
@Override
protected Collection<?> getChildren(final Object object) {
if (object instanceof ITreeElement) {
ITreeElement treeElement = (ITreeElement) object;
return treeElement.getChildren();
}
return Collections.emptyList();
}
@Override
protected boolean prepareDropMoveInsert(final Object parent, final Collection<?> children,
final int index) {
LinkItem parentLinkItem;
if (parent instanceof LinkItem) {
parentLinkItem = (LinkItem) parent;
} else {
return false;
}
Collection<Object> emfChildren = new ArrayList<Object>();
for (Object o : children) {
if (o instanceof ModelElementItem) {
ModelElementItem item = (ModelElementItem) o;
emfChildren.add(item.getEObject());
} else {
emfChildren.add(o);
}
}
// We don't want to move insert an object before or after
// itself
if (this.collection.contains(this.modelElementItem.getEObject())) {
this.dragCommand = IdentityCommand.INSTANCE;
this.dropCommand = UnexecutableCommand.INSTANCE;
} else if (emfChildren.containsAll(this.collection)) {
// ↑ if the dragged objects share a parent
this.dragCommand = IdentityCommand.INSTANCE;
// Create move commands for all the objects in the
// collection.
CompoundCommand compoundCommand = new CompoundCommand();
List<Object> before = new ArrayList<Object>();
List<Object> after = new ArrayList<Object>();
int i = 0;
for (Object object : emfChildren) {
if (this.collection.contains(object)) {
if (i < index) {
before.add(object);
} else if (i > index) {
after.add(object);
}
}
i++;
}
for (Object object : before) {
compoundCommand.append(MoveCommand.create(this.domain, parentLinkItem.getParent(),
parentLinkItem.getReference(), object, index - 1));
}
for (ListIterator<Object> objects = after.listIterator(after.size()); objects
.hasPrevious();) {
Object object = objects.previous();
compoundCommand.append(MoveCommand.create(this.domain, parentLinkItem.getParent(),
parentLinkItem.getReference(), object, index));
}
if (compoundCommand.getCommandList().isEmpty()) {
this.dropCommand = IdentityCommand.INSTANCE;
} else {
this.dropCommand = compoundCommand;
}
} else {
if (isCrossDomain()) {
EObject eObject = this.modelElementItem.getEObject();
Resource resource = eObject.eResource();
if (resource != null && resource.getResourceSet() != null) {
this.collection = DragAndDropUtils.translateCrossDomainObjects(this.collection,
resource.getResourceSet());
}
}
// Just remove the objects and add them.
this.dropCommand = AddCommand.create(this.domain, parentLinkItem.getParent(),
parentLinkItem.getReference(), this.collection, index);
if (analyzeForNonContainment(this.dropCommand)) {
// this.dropCommand.dispose();
// this.dropCommand = UnexecutableCommand.INSTANCE;
this.dragCommand = IdentityCommand.INSTANCE;
} else {
this.dragCommand = RemoveCommand.create(this.domain, this.collection);
}
}
boolean result = this.dragCommand.canExecute() && this.dropCommand.canExecute();
return result;
}
@Override
protected boolean prepareDropCopyInsert(final Object parent, final Collection<?> children,
final int index) {
LinkItem parentLinkItem;
if (parent instanceof LinkItem) {
parentLinkItem = (LinkItem) parent;
} else {
return false;
}
boolean result;
// We don't want to copy insert an object before or after
// itself
if (this.collection.contains(this.modelElementItem.getEObject())) {
this.dragCommand = IdentityCommand.INSTANCE;
this.dropCommand = UnexecutableCommand.INSTANCE;
result = false;
} else {
// Copy the collection
this.dragCommand = CopyCommand.create(this.domain, this.collection);
if (this.optimize) {
result = optimizedCanExecute();
if (result) {
this.optimizedDropCommandOwner = this.modelElementItem.getEObject();
}
} else {
if (this.dragCommand.canExecute() && this.dragCommand.canUndo()) {
this.dragCommand.execute();
this.isDragCommandExecuted = true;
// And add the copy.
this.dropCommand = AddCommand.create(this.domain, parentLinkItem.getParent(),
parentLinkItem.getReference(), this.dragCommand.getResult(), index);
if (analyzeForNonContainment(this.dropCommand)) {
this.dropCommand.dispose();
this.dropCommand = UnexecutableCommand.INSTANCE;
this.dragCommand.undo();
this.dragCommand.dispose();
this.isDragCommandExecuted = false;
this.dragCommand = IdentityCommand.INSTANCE;
}
result = this.dropCommand.canExecute();
} else {
this.dropCommand = UnexecutableCommand.INSTANCE;
result = false;
}
}
}
return result;
}
@Override
protected boolean prepareDropLinkInsert(final Object parent, final Collection<?> children,
final int index) {
this.dragCommand = IdentityCommand.INSTANCE;
this.dropCommand = UnexecutableCommand.INSTANCE;
return false;
}
@Override
protected boolean prepareDropMoveOn() {
if (isCrossDomain()) {
this.dragCommand = IdentityCommand.INSTANCE;
this.dropCommand = UnexecutableCommand.INSTANCE;
} else {
this.dropCommand = AddCommand.create(this.domain, this.modelElementItem.getEObject(),
null, this.collection);
if (analyzeForNonContainment(this.dropCommand)) {
this.dropCommand.dispose();
this.dropCommand = UnexecutableCommand.INSTANCE;
this.dragCommand = IdentityCommand.INSTANCE;
} else {
this.dragCommand = RemoveCommand.create(this.domain, this.collection);
}
}
boolean result = this.dragCommand.canExecute() && this.dropCommand.canExecute();
return result;
}
@Override
protected boolean prepareDropCopyOn() {
boolean result;
this.dragCommand = CopyCommand.create(this.domain, this.collection);
if (this.dragCommand.canExecute() && this.dragCommand.canUndo()) {
this.dragCommand.execute();
this.isDragCommandExecuted = true;
this.dropCommand = AddCommand.create(this.domain, this.modelElementItem.getEObject(),
null, this.dragCommand.getResult());
if (analyzeForNonContainment(this.dropCommand)) {
this.dropCommand.dispose();
this.dropCommand = UnexecutableCommand.INSTANCE;
this.dragCommand.undo();
this.dragCommand.dispose();
this.isDragCommandExecuted = false;
this.dragCommand = IdentityCommand.INSTANCE;
}
} else {
this.dropCommand = UnexecutableCommand.INSTANCE;
}
result = this.dragCommand.canExecute() && this.dropCommand.canExecute();
return result;
}
@Override
protected boolean prepareDropLinkOn() {
this.dragCommand = IdentityCommand.INSTANCE;
this.dropCommand = UnexecutableCommand.INSTANCE;
return false;
}
}