blob: b05ae8872a0305818af8def17a659a4ce4af830a [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.emf.clipboard.core;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMLResource;
/**
* A convenient default implementation of most of the features required of
* a clipboard support utility.
* <p>
* This class is intended to be extended by clients.
* </p>
*
* @author Christian W. Damus (cdamus)
*/
public class AbstractClipboardSupport
implements IClipboardSupport {
private static final Object NULL_TOKEN = Boolean.FALSE;
private final Map nameFeatureMap = new java.util.HashMap();
/**
* Initializes me.
*/
public AbstractClipboardSupport() {
super();
}
/**
* By default, there are no collisions in pasting.
*
* @return the {@link PasteAction#ADD} action, always
*/
public PasteAction getPasteCollisionAction(EClass eClass) {
return PasteAction.ADD;
}
/**
* By default, the following paste options are supported:
* <ul>
* <li>{@link PasteOption#NORMAL}: always</li>
* <li>others: never</li>
* </ul>
*/
public boolean hasPasteOption(EObject contextEObject,
EStructuralFeature eStructuralFeature, PasteOption pasteOption) {
if (pasteOption.equals(PasteOption.NORMAL)) {
return true;
} else {
return false;
}
}
/**
* By default, transient and derived references are never copied, and
* containment references always are copied.
*/
public boolean isCopyAlways(EObject context, EReference eReference,
Object value) {
if ((eReference.isTransient()) || (eReference.isDerived())) {
return false;
} else {
return eReference.isContainment();
}
}
/**
* By default, don't provide any child paste override behaviour.
*
* @return <code>false</code>, always
*/
public boolean shouldOverrideChildPasteOperation(EObject parentElement,
EObject childEObject) {
return false;
}
/**
* By default, don't provide any copy override behaviour.
*
* @return <code>false</code>, always
*/
public boolean shouldOverrideCopyOperation(Collection eObjects, Map hintMap) {
return false;
}
/**
* By default, don't provide any child paste override behaviour.
*
* @return <code>null</code>, always
*/
public OverridePasteChildOperation getOverrideChildPasteOperation(
PasteChildOperation overriddenChildPasteOperation) {
return null;
}
/**
* By default, don't provide any copy override behaviour.
*
* @return <code>null</code>, always
*/
public OverrideCopyOperation getOverrideCopyOperation(
CopyOperation overriddenCopyOperation) {
return null;
}
/**
* By default, don't exclude any objects from the copy operation.
*
* @return an empty collection
*/
public Collection getExcludedCopyObjects(Set eObjects) {
return Collections.EMPTY_SET;
}
/**
* By default, assumes that the <code>eObject</code> is attached to
* an XML resource, and returns that.
*/
public XMLResource getResource(EObject eObject) {
return (XMLResource) eObject.eResource();
}
/**
* By default, we always remember the containment feature of an object,
* unless it is an Ecore element (such as an annotation) or it is a
* detached element.
*
* @return <code>false</code> if the <code>eObject</code> is an Ecore
* object or is detached; <code>true</code>, otherwise
*/
public boolean shouldSaveContainmentFeature(EObject eObject) {
if (EcorePackage.eINSTANCE == eObject.eClass().getEPackage()) {
return false;
}
try {
eObject.eResource().getURIFragment(eObject);
} catch (Exception ex) {
return false;
}
return true;
}
/**
* By default, there is no post processing to be done.
*/
public void performPostPasteProcessing(Set pastedEObjects) {
// nothing to do
}
/**
* Obtains the cached name attribute of an eClass, or <code>null</code>
* if it has no attribute named "name".
*
* @param eClass an EClass
* @return the cached "name" attribute
*/
protected EAttribute getNameAttribute(EClass eClass) {
EAttribute result = null;
Object value = nameFeatureMap.get(eClass);
if (value != NULL_TOKEN) {
result = (EAttribute) value;
if (result == null) {
nameFeatureMap.put(eClass, NULL_TOKEN);
// look for an attribute named "name"
for (Iterator iter = eClass.getEAllAttributes().iterator(); iter.hasNext();) {
EAttribute next = (EAttribute) iter.next();
if ((next.getEType().getInstanceClass() == String.class)
&& next.getUpperBound() == 1
&& "name".equalsIgnoreCase(next.getName())) { //$NON-NLS-1$
result = next;
nameFeatureMap.put(eClass, result);
break;
}
}
}
}
return result;
}
/**
* By default, elements are nameable if they have an {@link EAttribute}
* named "name".
*/
public boolean isNameable(EObject eObject) {
return getNameAttribute(eObject.eClass()) != null;
}
public String getName(EObject eObject) {
EAttribute attr = getNameAttribute(eObject.eClass());
if (attr == null) {
throw new IllegalArgumentException("eObject not nameable"); //$NON-NLS-1$
}
return (String) eObject.eGet(attr);
}
public void setName(EObject eObject, String name) {
EAttribute attr = getNameAttribute(eObject.eClass());
if (attr == null) {
throw new IllegalArgumentException("eObject not nameable"); //$NON-NLS-1$
}
eObject.eSet(attr, name);
}
/**
* Simply removes an <code>eObject</code> from its container.
*/
public void destroy(EObject eObject) {
EcoreUtil.remove(eObject);
if (eObject.eResource() != null) {
// it was a cross-resource-contained element
eObject.eResource().getContents().remove(eObject);
}
}
/**
* Default implementation does nothing, for those applications that do not
* support creation notifications.
*/
public void sendCreateNotification(EObject eObject) {
// do nothing
}
/**
* @return <code>true</code> if the <code>reference</code>'s type is
* compatible with the <code>containedType</code>; <code>false</code>,
* otherwise
*/
public boolean canContain(EObject container, EReference reference,
EClass containedType) {
return reference.getEContainingClass().isSuperTypeOf(container.eClass())
&& reference.getEReferenceType().isSuperTypeOf(containedType);
}
}