/*************************************************** * Copyright (c) 2010 Atos Origin. * * 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: * Atos Origin - Initial API and implementation * ****************************************************/ package org.eclipse.papyrus.views.modelexplorer.commands; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; 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.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.emf.type.core.commands.SetValueCommand; import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest; import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.commands.DestroyElementPapyrusCommand; import org.eclipse.papyrus.infra.core.utils.PapyrusEcoreUtils; /** * The Class EObjectInheritanceCopyCommand. it takes an eobject in parameter and * copy all the elements contained in the source to the target and adds the * target to the container of the source */ public class EObjectInheritanceCopyCommand extends CompositeCommand { private final EObject sourceEObject; private final EObject targetEObject; private final TransactionalEditingDomain editingDomain; private Collection<Object> alreadyManaged = new LinkedList<Object>(); public EObjectInheritanceCopyCommand(EObject source, EClass target, TransactionalEditingDomain adapterFactoryEditingDomain) { super("Inheritance copy"); this.sourceEObject = source; this.targetEObject = target.getEPackage().getEFactoryInstance().create( target); this.editingDomain = adapterFactoryEditingDomain; if (sourceEObject == null || targetEObject == null || editingDomain == null) { throw new IllegalArgumentException( "Please provide non null arguments"); } init(); if (sourceEObject.eContainingFeature().isMany()) { replace(sourceEObject.eContainer(), sourceEObject, targetEObject, sourceEObject.eContainingFeature()); } else { add(new CustomSetCommand(editingDomain, sourceEObject.eContainer(), sourceEObject.eContainingFeature(), targetEObject, sourceEObject, sourceEObject.eContainingFeature())); add(new DestroyElementPapyrusCommand(new DestroyElementRequest( editingDomain, sourceEObject, false))); } } private void init() { modelCopy(sourceEObject, targetEObject); crossReference(sourceEObject, targetEObject); } /** * Model copy, copy the eobject source attributes to target's * * @param mixedDomain * the mixed domain * @param source * the source * @param target * the target */ private void modelCopy(EObject source, EObject target) { EClass eclass = source.eClass(); if (eclass != null) { EList<EStructuralFeature> eAllStructuralFeatures = eclass .getEAllStructuralFeatures(); for (EStructuralFeature e : eAllStructuralFeatures) { if (contains(target.eClass(), e) && isCompatible(e.getEType(), target.eClass() .getEStructuralFeature(e.getName()).getEType())) { manageFeature(source, target, e); } } } } /** * Contains. check if the target eclass contains a estructuralfeature with * the same name less rigorous can work for many cases * * @param target * the target * @param e * the e * * @return true, if successful */ private boolean contains(EClass target, EStructuralFeature e) { EList<EStructuralFeature> features = target.getEAllStructuralFeatures(); for (EStructuralFeature f : features) { if (f.getName().equals(e.getName())) { return true; } } return false; } /** * Manage feature for cross. * * @param mixedDomain * the mixed domain * @param theObjectWithCross * the the object with cross * @param source * the source * @param target * the target * @param structuralFeature * the structural feature */ private void manageFeatureForCross(EObject theObjectWithCross, EObject source, EObject target, EStructuralFeature structuralFeature) { boolean compatible = isCompatible(structuralFeature.getEType(), target .eClass()); if (compatible && structuralFeature.isChangeable() && !structuralFeature.isDerived()) { if (structuralFeature.isMany()) { replace(theObjectWithCross, source, target, structuralFeature); } else { add(new SetValueCommand(new SetRequest(editingDomain, theObjectWithCross, structuralFeature, target))); } } else if (!compatible) { if (structuralFeature.isMany()) { remove(theObjectWithCross, source, structuralFeature); } else { add(new SetValueCommand(new SetRequest(editingDomain, theObjectWithCross, structuralFeature, null))); } } } private void remove(EObject owner, Object source, EStructuralFeature structuralFeature) { if (!alreadyManaged.contains(source)) { if (owner == null && structuralFeature == null) { if (source instanceof EObject) { add(new DestroyElementPapyrusCommand(new DestroyElementRequest( editingDomain, (EObject) source, false))); } } else { Object value = owner.eGet(structuralFeature); if (value instanceof Collection<?>) { List<Object> newList = new ArrayList<Object>( (Collection<?>) value); newList.remove(source); add(new SetValueCommand(new SetRequest(editingDomain, owner, structuralFeature, newList))); } else if (source.equals(value)) { add(new SetValueCommand(new SetRequest(editingDomain, owner, structuralFeature, null))); } else { add(new SetValueCommand(new SetRequest(editingDomain, owner, structuralFeature, null))); } } alreadyManaged.add(source); } } private void replace(EObject owner, Object source, Object target, EStructuralFeature structuralFeature) { if (!alreadyManaged.contains(source)) { if (owner == null && structuralFeature == null) { if (source instanceof EObject) { add(new DestroyElementPapyrusCommand(new DestroyElementRequest( editingDomain, (EObject) source, false))); } } else { Object value = owner.eGet(structuralFeature); if (value instanceof Collection<?>) { List<Object> newList = new ArrayList<Object>( (Collection<?>) value); int index = newList.indexOf(source); if (index >= 0) { newList.remove(index); newList.add(index, target); add(new SetValueCommand(new SetRequest(editingDomain, owner, structuralFeature, newList))); } } else if (source.equals(value)) { add(new SetValueCommand(new SetRequest(editingDomain, owner, structuralFeature, target))); } else { add(new SetValueCommand(new SetRequest(editingDomain, owner, structuralFeature, target))); } } alreadyManaged.add(source); } } @Override public IStatus undo(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException { return super.undo(progressMonitor, info); } /** * Cross reference. Manage eobjects referencing the source eobject * * @param mixedDomain * the mixed domain * @param source * the source eobject * @param target * the target eobject */ private void crossReference(EObject source, EObject target) { Collection<EStructuralFeature.Setting> collection = PapyrusEcoreUtils.getUsages(source); if (collection != null) { for (EStructuralFeature.Setting nonNavigableInverseReference : collection) { EStructuralFeature structuralFeature = nonNavigableInverseReference .getEStructuralFeature(); if (!(nonNavigableInverseReference.getEObject() instanceof View)) { manageFeatureForCross(nonNavigableInverseReference .getEObject(), source, target, structuralFeature); } else if (nonNavigableInverseReference.getEObject() instanceof Diagram) { Diagram di = (Diagram) nonNavigableInverseReference .getEObject(); remove(null, di, null); } } } } /** * Checks if a type is compatible to another. * * @param type * the type * @param target * the target * * @return true, if is compatible */ public static boolean isCompatible(EClassifier type, EClassifier target) { Collection<EClassifier> types = new LinkedList<EClassifier>(); if (target instanceof EClass) { EClass eclass = (EClass) target; types.addAll(eclass.getEAllSuperTypes()); } if (!types.contains(target)) { types.add(target); } return types.contains(type); } /** * Manage a feature for the attribute's copy. * * @param mixedDomain * the mixed domain * @param source * the source * @param target * the target * @param feature * the e */ @SuppressWarnings("unchecked") private void manageFeature(EObject source, EObject target, EStructuralFeature feature) { EStructuralFeature targetFeature = getFeature(target, feature.getName()); if (feature.getUpperBound() <= targetFeature.getUpperBound() && feature.getLowerBound() >= targetFeature.getLowerBound()) { if (feature.isChangeable() && !feature.isDerived()) { Object value = source.eGet(feature); if (feature.isMany() && targetFeature.isMany()) { Collection<EObject> list = (Collection<EObject>) value; if (list != null && !list.isEmpty()) { Collection<EObject> newList = new LinkedList<EObject>(); newList.addAll(list); if (feature instanceof EReference && !((EReference) feature).isContainment()) { add(new SetValueCommand(new SetRequest( editingDomain, target, targetFeature, newList))); } else if (feature instanceof EReference && ((EReference) feature).isContainment()) { Collection<Object> toTreat = new LinkedList<Object>(); for (Object o : newList) { if (!alreadyManaged.contains(o)) { toTreat.add(o); alreadyManaged.add(o); } } add(new CustomAddCommand(editingDomain, target, targetFeature, newList, source, feature)); } } } else if (!feature.isMany() && !targetFeature.isMany()) { if (value != null) { if (!alreadyManaged.contains(value)) { alreadyManaged.add(value); add(new CustomSetCommand(editingDomain, target, targetFeature, value, source, feature)); } } } } } } /** * Gets a feature from a name * * @param eobject * the eobject * @param name * the name * * @return the feature */ private EStructuralFeature getFeature(EObject eobject, String name) { return eobject.eClass().getEStructuralFeature(name); } /** * Gets the result eobject. * * @return the result eobject */ public EObject getResultEobject() { return targetEObject; } /** * The Class CustomSetCommand. permits to change a value from an eobject to * eanother */ private class CustomSetCommand extends SetValueCommand { private EObject oldObject = null; private EStructuralFeature oldFeature = null; private Object oldValue = null; public CustomSetCommand(TransactionalEditingDomain domain, EObject owner, EStructuralFeature feature, Object value, EObject old, EStructuralFeature structuralFeature) { super(new SetRequest(domain, owner, feature, value)); oldObject = old; oldFeature = structuralFeature; oldValue = value; } @Override protected IStatus doUndo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { IStatus result = super.doUndo(monitor, info); oldObject.eSet(oldFeature, oldValue); return result; } } /** * The Class CustomSetCommand. permits to change a value from an eobject to * eanother */ private class CustomAddCommand extends SetValueCommand { private EObject oldObject = null; private EStructuralFeature oldFeature; private EStructuralFeature newFeature; public CustomAddCommand(TransactionalEditingDomain editingDomain, EObject target, EStructuralFeature targetFeature, Collection<EObject> newList, EObject source, EStructuralFeature e) { super(new SetRequest(editingDomain, target, targetFeature, newList)); oldObject = source; oldFeature = e; newFeature = targetFeature; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override protected IStatus doUndo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { Object values = getElementToEdit().eGet(newFeature); IStatus result = super.doUndo(monitor, info); // this test permit to avoid modification from other command // if getOwner list is empty it will perform error we avoid it if (values instanceof Collection<?> && !((Collection<?>) values).isEmpty()) { Collection<?> collection = (Collection<?>) values; Collection<Object> collecOldObject = (Collection) oldObject .eGet(oldFeature); for (Object o : collection) { if (!collecOldObject.contains(o)) { collecOldObject.add(o); } } } return result; } } }