/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.core.container;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.CopyCommand;
import org.eclipse.emf.edit.command.PasteFromClipboardCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.teiid.designer.core.ModelEditorImpl;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.metamodel.IPasteContributor;
import org.teiid.designer.core.resource.EmfResource;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.metamodels.core.AnnotationContainer;
import org.teiid.designer.metamodels.core.CorePackage;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.transformation.MappingClassSetContainer;
import org.teiid.designer.metamodels.transformation.TransformationContainer;
import org.teiid.designer.metamodels.transformation.TransformationPackage;
/**
* This command copies the objects on the clipboard (as well as related objects)
* and adds them in the specified location(s). Related objects include
* {@link org.teiid.designer.metamodels.core.Annotation annotations} and
* {@link org.teiid.designer.metamodels.transformation.TransformationMappingRoot transformations}.
* <p>
* This class is actually a compound command that is comprise of an actual
* {@link org.eclipse.emf.edit.command.PasteFromClipboardCommand} as well as commands to
* copy the related objects and place into their appropriate locations.
* </p><p>
* Note that the command framework is written to always uses the {@link Command} interface,
* and never concrete commands. Therefore, it is possible for this class to
* extend {@link org.eclipse.emf.common.command.CompoundCommand} rather than
* {@link org.eclipse.emf.edit.command.PasteFromClipboardCommand}.
* </p>
*
* @since 8.0
*/
public class PasteWithRelatedFromClipboardCommand extends CompoundCommand {
// ===========================================================================================================================
// Constants
/**
* This caches the label.
*/
protected static final String LABEL = ModelerCore.Util.getString("PasteWithRelatedFromClipboardCommand.Label"); //$NON-NLS-1$
/**
* This caches the description.
*/
protected static final String DESCRIPTION = ModelerCore.Util.getString("PasteWithRelatedFromClipboardCommand.Description"); //$NON-NLS-1$
private static final String PASTE_CONTRIBUTOR_EXT_PT = "pasteContributor"; //$NON-NLS-1$
private static final String NAME_ATTR = "name"; //$NON-NLS-1$
// ===========================================================================================================================
// Static Controller Methods
/**
* This creates a command to add copies from the clipboard to the specified feature of the owner.
*/
public static Command create(EditingDomain domain, Object owner, Object feature) {
return create(domain, owner, feature, CommandParameter.NO_INDEX);
}
/**
* This creates a command to add copies from the clipboard to the specified feature of the owner and at the given index.
*/
public static Command create(EditingDomain domain, Object owner, Object feature, int index) {
if (domain == null)
{
return new PasteWithRelatedFromClipboardCommand(domain, owner, feature, index, true);
}
Command command =
domain.createCommand(PasteFromClipboardCommand.class, new CommandParameter(owner, feature, Collections.EMPTY_LIST, index));
return command;
}
// ===========================================================================================================================
// Variables
/**
* This it the editing domain.
*/
protected EditingDomain domain;
/**
* This is object where the clipboard copy is pasted.
*/
protected Object owner;
/**
* This is feature of the owner where the clipboard copy is pasted.
*/
protected Object feature;
/**
* This is index in the feature of the owner where the clipboard copy is pasted.
*/
protected int index;
/**
* This controls whether or not to optimize the canExecute (prepare)
*/
protected boolean optimize;
protected PasteFromClipboardWithMappingCommand pasteCommand;
// ===========================================================================================================================
// Constructors
/**
* This constructs an instance from the domain, which provides access the clipboard collection
* via {@link EditingDomain#getCommandStack}.
*/
public PasteWithRelatedFromClipboardCommand(final EditingDomain domain, final Object owner,
final Object feature, final int index) {
this(domain, owner, feature, index, true);
}
public PasteWithRelatedFromClipboardCommand(final EditingDomain domain, final Object owner,
final Object feature, final int index, final boolean optimize) {
super(MERGE_COMMAND_ALL, LABEL, DESCRIPTION);
// Initialize the variables ...
this.domain = domain;
this.owner = owner;
this.feature = feature;
this.index = index;
this.optimize = optimize;
// Create and add the main PasteFromClipboardCommand ...
this.pasteCommand = new PasteFromClipboardWithMappingCommand(this.domain,this.owner,this.feature,this.index);
append(this.pasteCommand);
}
// ===========================================================================================================================
// Controller Methods
/**
* @see org.eclipse.emf.common.command.CompoundCommand#execute()
*/
@Override
public void execute() {
// Execute any existing commands ...
super.execute();
// ------------------------------------------------------
// Now, see if there are additional things to be done ...
// ------------------------------------------------------
ModelContents clipboardModelContents = null;
if ( this.domain instanceof ContainerEditingDomain ) {
final ContainerEditingDomain ctnrDomain = (ContainerEditingDomain)this.domain;
clipboardModelContents = ctnrDomain.getClipboardModelContents(false);
if ( clipboardModelContents != null ) {
// Find the content helper for the target location ...
Resource targetResource = null;
if ( this.owner instanceof Resource ) {
targetResource = (Resource)this.owner;
} else if ( this.owner instanceof EObject ) {
targetResource = ((EObject)this.owner).eResource();
} else if ( this.owner instanceof ModelResource ) {
try {
targetResource = ((ModelResource)this.owner).getEmfResource();
} catch (ModelWorkspaceException e1) {
ModelerCore.Util.log(e1); // do nothing else
}
}
// Continue with the processing only if the target resource was found
if ( targetResource != null && targetResource instanceof EmfResource ) {
final ModelContents targetContents = ((EmfResource)targetResource).getModelContents();
doCreateAdditionalCommands(clipboardModelContents, targetContents);
// Check if objects were copied (vs. cut)
Map map = ctnrDomain.getClipboardContentsOriginalToCopyMapping();
if (map != null) {
// Allow paste contributors to contribute ...
final IConfigurationElement[] elems =
Platform.getExtensionRegistry().getConfigurationElementsFor(ModelerCore.PLUGIN_ID,
PASTE_CONTRIBUTOR_EXT_PT);
if (elems != null) {
// Create map from original to pasted objects
map = ctnrDomain.getClipboardContentsCopyToOriginalMapping();
final CopyCommand.Helper helper = this.pasteCommand.getHelper();
final Map origPastedMap = new HashMap(map.size());
for (final Iterator iter = helper.entrySet().iterator(); iter.hasNext();) {
final Entry entry = (Entry)iter.next();
origPastedMap.put(map.get(entry.getKey()), entry.getValue());
}
// Pass map & target metamodel URI to contributors
for (int ndx = elems.length; --ndx >= 0;) {
try {
final Object obj = elems[ndx].createExecutableExtension(NAME_ATTR);
if (obj instanceof IPasteContributor) {
targetContents.getAnnotationContainer(true);
final String uri = targetContents.getModelAnnotation().getPrimaryMetamodelUri();
((IPasteContributor)obj).contribute(origPastedMap, uri);
}
} catch (final CoreException err) {
ModelerCore.Util.log(err);
}
}
}
}
}
}
}
}
/**
* Create additional commands for copying the supplied additional "related" objects, and
* add-and-execute them (via the {@link PasteFromClipboard#appendAndExecute(}).
* @param clipboardModelContents the content helper for the clipboard; never null
* @param targetContents the content helper for the Resource in which the object is being copied
* and pasted; never null
*/
protected void doCreateAdditionalCommands(final ModelContents clipboardModelContents, final ModelContents targetContents) {
// Create the copy command for all of the annotations ...
final AnnotationContainer clipboardAnnContainer = clipboardModelContents.getAnnotationContainer(false);
if ( clipboardAnnContainer != null && clipboardAnnContainer.getAnnotations().size() != 0 ) {
final AnnotationContainer container = targetContents.getAnnotationContainer(true);
final EStructuralFeature feature = CorePackage.eINSTANCE.getAnnotationContainer_Annotations();
copyAndAdd(clipboardAnnContainer.getAnnotations(), container, feature);
}
// If target in PHYSICAL model (i.e. not virtual) then we don't want to do these next two steps
if( targetContents.getModelAnnotation().getModelType() == ModelType.VIRTUAL_LITERAL) {
// Create the copy command for all of the mapping classes ...
final MappingClassSetContainer clipboardMCSetContainer = clipboardModelContents.getMappingClassSetContainer(false);
if ( clipboardMCSetContainer != null && clipboardMCSetContainer.getMappingClassSets().size() != 0 ) {
final MappingClassSetContainer container = targetContents.getMappingClassSetContainer(true);
final EStructuralFeature feature = TransformationPackage.eINSTANCE.getMappingClassSetContainer_MappingClassSets();
copyAndAdd(clipboardMCSetContainer.getMappingClassSets(), container, feature);
}
// Create the copy command for all of the transformations ...
final TransformationContainer clipboardTransContainer = clipboardModelContents.getTransformationContainer(false);
if ( clipboardTransContainer != null && clipboardTransContainer.getTransformationMappings().size() != 0 ) {
final TransformationContainer container = targetContents.getTransformationContainer(true);
final EStructuralFeature feature = TransformationPackage.eINSTANCE.getTransformationContainer_TransformationMappings();
copyAndAdd(clipboardTransContainer.getTransformationMappings(), container, feature);
}
}
}
protected void copyAndAdd(final Collection additionalObjects, final EObject container, final EStructuralFeature feature) {
final CopyCommand.Helper helper = this.pasteCommand.getHelper();
final Command copyCommand = ModelEditorImpl.createCopyCommand(this.domain,additionalObjects,helper);
final boolean copied = this.appendAndExecute(copyCommand);
if ( copied ) {
// Create the add command to place all of the annotations into the annotation container ...
final Collection copiedAnnotations = copyCommand.getResult();
final Command addCommand = AddCommand.create(this.domain,container, feature, copiedAnnotations);
final boolean added = this.appendAndExecute(addCommand);
if ( !added ) {
// Failed, but the copied objects will be left without a parent
// and will simply be garbage collected. However, log anyway ...
final URI uri = EcoreUtil.getURI(container);
final Object[] params = new Object[]{new Integer(copiedAnnotations.size()),
feature.getName(),
uri != null ? uri.trimFragment().toString() : "<unknown>"}; //$NON-NLS-1$
final String msg = ModelerCore.Util.getString("PasteWithRelatedFromClipboardCommand.Failed_to_paste_{0}_{1}_from_clipboard_to_{2}",params); //$NON-NLS-1$
ModelerCore.Util.log(msg);
}
}
}
}