/*
* 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.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.CopyCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.designer.core.FindRelatedObjectsToBeCopied;
import org.teiid.designer.core.ModelEditorImpl;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.core.util.ModelVisitorProcessor;
import org.teiid.designer.metamodels.core.Annotation;
import org.teiid.designer.metamodels.core.AnnotationContainer;
import org.teiid.designer.metamodels.core.CoreFactory;
import org.teiid.designer.metamodels.core.CorePackage;
import org.teiid.designer.metamodels.transformation.MappingClassSet;
import org.teiid.designer.metamodels.transformation.MappingClassSetContainer;
import org.teiid.designer.metamodels.transformation.TransformationContainer;
import org.teiid.designer.metamodels.transformation.TransformationFactory;
import org.teiid.designer.metamodels.transformation.TransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TransformationPackage;
/**
* This command copies the supplied objects as well as "related" objects (e.g., {@link Annotation},
* {@link org.teiid.designer.metamodels.transformation.TransformationMapping} instances) to the clipboard.
* The "related" objects are not placed on the clipboard per se, but instead are placed into
* the {@link org.teiid.designer.core.container.ContainerEditingDomain#getClipboardModelContents(boolean) ContainerEditingDomain's clipboard ModelContents}
* object (which is reset each time the clipboard contents are set).
* @see org.teiid.designer.core.container.PasteWithRelatedFromClipboardCommand
*
* @since 8.0
*/
public class CopyWithRelatedToClipboardCommand extends CompoundCommand {
private final Collection originals;
private final CopyToClipboardCommandWithMapping mainCopyCommand;
private final EditingDomain domain;
/**
* Construct an instance of CopyToClipboardCommandWithMapping.
* @param domain
* @param collection
*/
public CopyWithRelatedToClipboardCommand(final EditingDomain domain, final Collection collection) {
super();
this.originals = collection;
this.domain = domain;
this.mainCopyCommand = new CopyToClipboardCommandWithMapping(domain,collection);
append(this.mainCopyCommand);
}
@Override
public void execute() {
super.execute();
if ( this.originals != null && this.originals.size() != 0 ) {
doCopyRelatedObjects();
}
}
protected void doCopyRelatedObjects() {
if ( this.domain instanceof ContainerEditingDomain ) {
// ------------------------------------------------------
// Now, see if there are additional things to be done ...
// ------------------------------------------------------
// Iterate through the original objects, and find any additional objects that should be copied ...
final FindRelatedObjectsToBeCopied visitor = new FindRelatedObjectsToBeCopied();
final ModelVisitorProcessor processor = new ModelVisitorProcessor(visitor);
try {
processor.walk(this.originals,ModelVisitorProcessor.DEPTH_INFINITE);
} catch (ModelerCoreException e) {
ModelerCore.Util.log(e);
}
// See if there are any additional objects to be copied ...
final Collection additionalObjs = visitor.getAdditionalObjects();
if ( additionalObjs.size() != 0 ) {
final ModelContents modelContents = ((ContainerEditingDomain)this.domain).getClipboardModelContents(true);
this.doCreateAdditionalCommands(additionalObjs,modelContents);
}
}
}
/**
* Create additional commands for copying the supplied additional "related" objects, and
* add-and-execute them (via the {@link PasteFromClipboard#appendAndExecute(}).
* @param additionalObjs the original "related" objects that are to be copied and added to the
* correct location; never null
* @param targetContents the content helper for the Resource in which the object is being copied
* and pasted; never null
* @return the subset of <code>additionalObjs</code> that were not handled by this implementation;
* never null
*/
protected Collection doCreateAdditionalCommands(final Collection additionalObjs, final ModelContents targetContents) {
if ( additionalObjs.isEmpty() ) {
return additionalObjs;
}
// Find all of the annotations and transformations ...
final Set annotations = new HashSet();
final Set transformations = new HashSet();
final Set mappingClassSets = new HashSet();
final List remaining = new LinkedList();
final Iterator iter = additionalObjs.iterator();
while (iter.hasNext()) {
final Object additionalObj = iter.next();
if ( additionalObj instanceof Annotation ) {
annotations.add(additionalObj);
} else if ( additionalObj instanceof TransformationMappingRoot ) {
transformations.add(additionalObj);
} else if ( additionalObj instanceof MappingClassSet ) {
mappingClassSets.add(additionalObj);
} else {
remaining.add(additionalObj);
}
}
// Create the copy command for all of the annotations ...
if ( annotations.size() != 0 ) {
// Note: container will probably be null due to changes in the following underlying method call.
// This is due to the targetContents' Resource == NULL (see ModelResourceContainerFactory.getAnnotationContainer());
AnnotationContainer container = targetContents.getAnnotationContainer(true);
if( container == null ) {
// it's null, so we'll new one up via the CoreFactory....
container = CoreFactory.eINSTANCE.createAnnotationContainer();
// since one wasn't found, we need to create a temporary one and add to contents
targetContents.getAllRootEObjects().add(container);
}
final EStructuralFeature feature = CorePackage.eINSTANCE.getAnnotationContainer_Annotations();
copyAndAdd(annotations, container, feature);
}
// Create the copy command for all of the mapping class sets ...
if ( mappingClassSets.size() != 0 ) {
// Note: container will probably be null due to changes in the following underlying method call.
// This is due to the targetContents' Resource == NULL (see ModelResourceContainerFactory.getMappingClassSetContainer());
MappingClassSetContainer container = targetContents.getMappingClassSetContainer(true);
if( container == null ) {
// it's null, so we'll new one up via the TransformationFactory....
container = TransformationFactory.eINSTANCE.createMappingClassSetContainer();
// since one wasn't found, we need to create a temporary one and add to contents
targetContents.getAllRootEObjects().add(container);
}
final EStructuralFeature feature = TransformationPackage.eINSTANCE.getMappingClassSetContainer_MappingClassSets();
copyAndAdd(mappingClassSets, container, feature);
}
// Create the copy command for all of the transformations ...
if ( transformations.size() != 0 ) {
// Note: container will probably be null due to changes in the following underlying method call.
// This is due to the targetContents' Resource == NULL (see ModelResourceContainerFactory.getMappingClassSetContainer());
TransformationContainer container = targetContents.getTransformationContainer(true);
if( container == null ) {
// it's null, so we'll new one up via the TransformationFactory....
container = TransformationFactory.eINSTANCE.createTransformationContainer();
// since one wasn't found, we need to create a temporary one and add to contents
targetContents.getAllRootEObjects().add(container);
}
final EStructuralFeature feature = TransformationPackage.eINSTANCE.getTransformationContainer_TransformationMappings();
copyAndAdd(transformations, container, feature);
}
return null;
}
protected void copyAndAdd(final Set additionalObjects, final EObject container, final EStructuralFeature feature) {
final CopyCommand.Helper helper = this.mainCopyCommand.getCopyKeyedByOriginalMap();
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 Object[] params = new Object[]{new Integer(copiedAnnotations.size()),feature.getName()};
final String msg = ModelerCore.Util.getString("CopyWithRelatedToClipboardCommand.Failed_to_add_{0}_copied_{1}_to_clipboard",params); //$NON-NLS-1$
ModelerCore.Util.log(msg);
}
}
}
}