/*****************************************************************************
* Copyright (c) 2009 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.pastemanager.command;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.DuplicateElementsRequest;
import org.eclipse.gmf.runtime.notation.Bounds;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.LayoutConstraint;
import org.eclipse.gmf.runtime.notation.Shape;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.core.utils.BusinessModelResolver;
import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
/**
* this command is used to wrap a copy command. it allows set a new owner for views.
*/
public class PapyrusDuplicateWrapperCommand extends AbstractTransactionalCommand {
/** the new container for the shape */
protected View container = null;
/** Command that owns this duplicate command */
protected ICommand duplicateEObjectsCommandOwner = null;
/** list of object to duplicate */
protected List<Object> eObjectsToBeDuplicated = null;
/** Constant used as a key for the parameters map of the duplication request */
public static final String ADDITIONAL_DUPLICATED_ELEMENTS = "Additional_Duplicated_Elements";
/**
* Constructor.
*
* @param editingDomain
* @param label
* @param eObjectsToBeDuplicated
* @param subCommand
* @param container
*/
public PapyrusDuplicateWrapperCommand(TransactionalEditingDomain editingDomain, String label, List<Object> eObjectsToBeDuplicated, ICommandProxy subCommand, View container) {
super(editingDomain, label, null);
this.container = container;
this.eObjectsToBeDuplicated = eObjectsToBeDuplicated;
this.duplicateEObjectsCommandOwner = lookForDuplicateCommandOwner(subCommand);
}
/**
* Verifies that the container of all the original objects can contain
* multiple objects.
*/
@Override
@SuppressWarnings("rawtypes")
public boolean canExecute() {
for(Iterator iter = eObjectsToBeDuplicated.iterator(); iter.hasNext();) {
EObject original = (EObject)iter.next();
//In the case of cut the owner does not exist
if(original.eContainer() == null) {
return true;
} else {
EReference reference = original.eContainmentFeature();
if(reference == null || !FeatureMapUtil.isMany(original.eContainer(), reference)) {
return false;
}
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("rawtypes")
protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
duplicateEObjectsCommandOwner.execute(progressMonitor, info);
CommandResult result = duplicateEObjectsCommandOwner.getCommandResult();
//reassociation to the new container
if(result.getReturnValue() instanceof List) {
Iterator resultIterator = ((List)result.getReturnValue()).iterator();
while(resultIterator.hasNext()) {
Object currentResult = resultIterator.next();
// the result of a copy is a map
if(currentResult instanceof Map) {
Map duplicatedObject = (Map)currentResult;
Iterator iterator = duplicatedObject.values().iterator();
// for each view, a container is set if it is null
// if this is a shape a new position is set in order to avoid superposition
while(iterator.hasNext()) {
Object object = iterator.next();
if(object instanceof View) {
View duplicatedView = (View)object;
if(object instanceof Shape) {
LayoutConstraint layoutConstraint = ((Shape)object).getLayoutConstraint();
if(layoutConstraint instanceof Bounds) {
((Bounds)layoutConstraint).setX(((Bounds)layoutConstraint).getX() + 10);
((Bounds)layoutConstraint).setY(((Bounds)layoutConstraint).getY() + 10);
}
}
if(duplicatedView.eContainer() == null && container != null) {
ViewUtil.insertChildView(container, duplicatedView, -1, true);
}
}
}
}
}
} else if(result.getReturnValue() instanceof Map) { // perhaps not a list in case of simple ICommand, result value should be a map
Map duplicatedObject = (Map)result.getReturnValue();
Iterator iterator = duplicatedObject.values().iterator();
// for each view, a container is set if it is null
// if this is a shape a new position is set in order to avoid superposition
while(iterator.hasNext()) {
Object object = iterator.next();
if(object instanceof Diagram) {
Diagram diagramView = (Diagram)object;
if(container != null && container.eResource() != null) {
container.eResource().getContents().add(diagramView);
}
} else if(object instanceof View) {
View duplicatedView = (View)object;
if(object instanceof Shape) {
LayoutConstraint layoutConstraint = ((Shape)object).getLayoutConstraint();
if(layoutConstraint instanceof Bounds) {
((Bounds)layoutConstraint).setX(((Bounds)layoutConstraint).getX() + 10);
((Bounds)layoutConstraint).setY(((Bounds)layoutConstraint).getY() + 10);
}
}
if(duplicatedView.eContainer() == null && container != null) {
ViewUtil.insertChildView(container, duplicatedView, -1, true);
}
}
}
ICommand externalObjectsDuplicateCommand = getExternalObjectsDuplicateCommand((Map<?, ?>)result.getReturnValue());
if(externalObjectsDuplicateCommand != null && externalObjectsDuplicateCommand.canExecute()) {
IStatus status = externalObjectsDuplicateCommand.execute(progressMonitor, info);
if(!status.isOK()) {
return CommandResult.newErrorCommandResult(status.getException());
}
}
}
return result;
}
/**
* this class is used to look for the basic eobject duplicate command
*
* @param command
* that contains normally the duplicated command
* @return the duplicate command
*/
protected ICommand lookForDuplicateCommandOwner(ICommandProxy command) {
return command.getICommand();
}
/**
* Returns the list of external objects to duplicate
*
* @return the list of external objects to duplicate or an empty list if not elements are found to add.
*/
protected ICommand getExternalObjectsDuplicateCommand(Map duplicatedElementsMap) {
CompositeCommand result = new CompositeCommand("Duplicate External Objects");
Set<Object> duplicatedExternalElements = new HashSet<Object>();
for(Object o : duplicatedElementsMap.keySet()) {
if(o instanceof EObject) {
EObject object = (EObject)o;
DuplicateElementsRequest request = new DuplicateElementsRequest(Collections.singletonList(object));
request.setAllDuplicatedElementsMap(duplicatedElementsMap);
request.setParameter(PapyrusDuplicateWrapperCommand.ADDITIONAL_DUPLICATED_ELEMENTS, duplicatedExternalElements);
request.setParameter("Target_Owner", BusinessModelResolver.getInstance().getBusinessModel(container));
IElementEditService service = ElementEditServiceUtils.getCommandProvider(object);
ICommand command = service.getEditCommand(request);
if(command != null) {
result.add(command);
}
}
}
return (result.isEmpty()) ? null : result.reduce();
}
}