/*****************************************************************************
* Copyright (c) 2011 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.commands.command;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
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.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.command.AbstractCommand;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.DuplicateElementsRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.MoveRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
import org.eclipse.papyrus.uml.commands.Activator;
import org.eclipse.papyrus.uml.tools.utils.NamedElementUtil;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.util.UMLUtil;
;
/**
* this handler has in charge to exexute the paste of UML element with their applied stereotypes
*
*/
public class PasteElementCommand extends AbstractCommand {
protected ArrayList<EObject> eobjectTopaste = null;
protected ArrayList<EObject> stereotypeApplicationTopaste = null;
protected EObject targetOwner;
protected CompositeCommand command;
//the prefix for the duplicated object
protected String COPY_OF = "CopyOf";
/**
* get the command do the paste on the target owner
*
* @param domain
* the editing owner
* @param targetOwner
* the element where the paste will be done
*/
public PasteElementCommand(EditingDomain domain, EObject targetOwner) {
super();
if(domain.getClipboard() != null) {
//1. get Data from the clipboard
Collection<Object> rawData = domain.getClipboard();
//2. filter only EObject
ArrayList<EObject> eobjectsTopaste = new ArrayList<EObject>();
Iterator<Object> iterData = rawData.iterator();
while(iterData.hasNext()) {
Object object = iterData.next();
if(object instanceof EObject) {
eobjectsTopaste.add((EObject)object);
}
}
// 2b retrieve now the original stereotype application
List<EObject> originalStereotypeApplications = new ArrayList<EObject>();
Iterator<EObject> selecIterator = eobjectsTopaste.iterator();
while(selecIterator.hasNext()) {
EObject eObject = selecIterator.next();
if(eObject instanceof Element) {
originalStereotypeApplications.addAll(((Element)eObject).getStereotypeApplications());
}
//copy stereotype contained into
Iterator<EObject> iter = eObject.eAllContents();
while(iter.hasNext()) {
EObject subeObject = iter.next();
if(subeObject instanceof Element) {
originalStereotypeApplications.addAll(((Element)subeObject).getStereotypeApplications());
}
}
}
eobjectsTopaste.addAll(originalStereotypeApplications);
//3. Copy all eObjects (inspired from PasteFromClipboardCommand)
// Collection<EObject> duplicatedObject = EcoreUtil.copyAll(eobjectsTopaste);
EcoreUtil.Copier copier = new EcoreUtil.Copier();
copier.copyAll(eobjectsTopaste);
copier.copyReferences();
Map<EObject, EObject> duplicatedObjects = new HashMap<EObject, EObject>();
duplicatedObjects.putAll(copier);
//4. filter eobject that are UML elements and application of stereotypes
Iterator<EObject> iter = duplicatedObjects.values().iterator();
eobjectTopaste = new ArrayList<EObject>();
stereotypeApplicationTopaste = new ArrayList<EObject>();
while(iter.hasNext()) {
EObject eObject = iter.next();
boolean isaUMLElement = false;
if(eObject instanceof Element) {
isaUMLElement = true;
}
//functionality that comes from UML2 plugins
Stereotype st = UMLUtil.getStereotype(eObject);
if(isaUMLElement && !originalStereotypeApplications.contains(eObject)) {
eobjectTopaste.add(eObject);
}
}
// 4b retrieve stereotypeapplications to paste
Iterator<EObject> stereotypeIterator = originalStereotypeApplications.listIterator();
while(stereotypeIterator.hasNext()) {
EObject originalStereotypeApp = stereotypeIterator.next();
EObject duplicateStereotype = duplicatedObjects.get(originalStereotypeApp);
if(duplicateStereotype == null) {
Activator.log.debug("warning a stereotype could not be copied/paste : " + originalStereotypeApp);
} else {
stereotypeApplicationTopaste.add(duplicateStereotype);
}
}
this.targetOwner = targetOwner;
//5. prepare the move command to move UML element to their new owner
//Nota: move only the "root" semantic elements to be paste
List<EObject> objectsToMove = new ArrayList<EObject>();
Iterator<EObject> it = eobjectsTopaste.iterator();
while(it.hasNext()) {
EObject eObject = it.next();
boolean isaUMLElement = false;
if(eObject instanceof Element) {
isaUMLElement = true;
}
//functionality that comes from UML2 plugins
if((isaUMLElement && !originalStereotypeApplications.contains(eObject))) {// UML element, but not a stereotype => should be moved
// this is one of the original elements to paste, not a stereotype.
// the copy of this one should be moved
EObject copyObject = duplicatedObjects.get(eObject);
if(copyObject != null) {
objectsToMove.add(copyObject);
}
}
}
MoveRequest moveRequest = new MoveRequest(targetOwner, objectsToMove);
IElementEditService provider = ElementEditServiceUtils.getCommandProvider(targetOwner);
if(provider != null) {
command = new CompositeCommand("Copy Object");
command.compose(provider.getEditCommand(moveRequest));
}
//5 bis. Rename the duplicated objects (only the root elements that are copied, no need to rename *all* nested elements)
for(int i = 0; i < objectsToMove.size(); i++) {
EObject element = objectsToMove.get(i);
if(element instanceof NamedElement && domain instanceof TransactionalEditingDomain) {
String newName = NLS.bind(COPY_OF + "_{0}_", ((NamedElement)element).getName());
String incrementedName = NamedElementUtil.getDefaultNameWithIncrementFromBase(newName, targetOwner.eContents());
SetRequest renameRequest = new SetRequest((TransactionalEditingDomain)domain, element, UMLFactory.eINSTANCE.getUMLPackage().getNamedElement_Name(), incrementedName);
if(provider != null && command != null) {
command.compose(provider.getEditCommand(renameRequest));
}
}
}
ICommand externalObjectsDuplicateCommand = getExternalObjectsDuplicateCommand(duplicatedObjects, targetOwner);
if(externalObjectsDuplicateCommand != null && command != null) {
command.compose(externalObjectsDuplicateCommand);
}
}
}
/**
* {@inheritDoc}
*/
public void execute() {
// for steps 1. 2. 3. 4. 5. see constructor
//6. execute the move command for UML element
if(command != null) {
try {
command.execute(new NullProgressMonitor(), null);
} catch (ExecutionException e) {
Activator.log.error(e);
}
}
//7. move stereotypes applications into the resource
Iterator<EObject> stereoApplIter = stereotypeApplicationTopaste.iterator();
while(stereoApplIter.hasNext()) {
EObject eObject = stereoApplIter.next();
targetOwner.eResource().getContents().add(eObject);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean canExecute() {
if(command == null) {
return false;
}
return command.canExecute();
}
/**
* {@inheritDoc}
*/
public void redo() {
// for steps 1. 2. 3. 4. 5. see constructor
//6. execute the move command for UML element
if(command != null) {
try {
command.redo(new NullProgressMonitor(), null);
} catch (ExecutionException e) {
Activator.log.error(e);
}
}
//7. move stereotype application into the resource
Iterator<EObject> stereoApplIter = stereotypeApplicationTopaste.iterator();
while(stereoApplIter.hasNext()) {
EObject eObject = stereoApplIter.next();
targetOwner.eResource().getContents().add(eObject);
}
}
/**
* {@inheritDoc}
*/
@Override
public void undo() {
// for steps 1. 2. 3. 4. 5. see constructor
//6. Undo the move command for UML element
try {
IProgressMonitor monitor = new NullProgressMonitor();
command.undo(monitor, null);
} catch (ExecutionException e) {
Activator.log.error(e);
}
//7. remove stereotype application from the resource
Iterator<EObject> stereoApplIter = stereotypeApplicationTopaste.iterator();
while(stereoApplIter.hasNext()) {
EObject eObject = stereoApplIter.next();
targetOwner.eResource().getContents().remove(eObject);
}
}
/**
* 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, EObject targetOwner) {
CompositeCommand result = new CompositeCommand("Additional Duplications");
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("Additional_Duplicated_Elements", duplicatedExternalElements);
request.setParameter("Target_Owner", targetOwner);
IElementEditService service = ElementEditServiceUtils.getCommandProvider(object);
ICommand command = service.getEditCommand(request);
if(command != null) {
result.add(command);
}
}
}
return result.isEmpty() ? null : result.reduce();
}
}