/* * 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.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.IStatus; 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.ModelEditor; import org.teiid.designer.core.ModelEditorImpl; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.search.ModelWorkspaceSearch; import org.teiid.designer.core.util.ModelContents; 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 cuts 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 CutWithRelatedToClipboardCommand extends CompoundCommand { private final Collection originals; private final Command mainCommand; private final EditingDomain domain; private final List additionalObjs; private ModelContents clipboardModelContents = null; /** * Construct an instance of CopyToClipboardCommandWithMapping. * @param domain * @param collection */ public CutWithRelatedToClipboardCommand( final Command command, final EditingDomain domain, final Collection collection) { super(); this.originals = collection; this.domain = domain; this.mainCommand = command; // gather up related objects for the objects in the originals collection this.additionalObjs = ((ModelEditorImpl) ModelerCore.getModelEditor()).findRelatedObjects(this.originals, this.domain); try { // remove references to objects in the collection; create and append // remove commands for the objects that need to be removed in the cut handleReferencingObjects(); } catch (ModelerCoreException err) { } if ( this.originals != null && this.originals.size() != 0 ) { // create add commands for related objects (in the additionalObjects list) this.clipboardModelContents = createAddCommandsForRelatedObjects(); } // append the main command (passed into the constructor; most likely another cut command for the main EObject // that is being removed and added to the clipboard) append(this.mainCommand); } protected void handleReferencingObjects() throws ModelerCoreException { ModelEditor modelEditor = ModelerCore.getModelEditor(); final List originalsToProcess = new ArrayList(this.originals.size()); final List additionalCommands = new ArrayList(); ModelWorkspaceSearch workspaceSearch = new ModelWorkspaceSearch(); // Process only those objects that are not orphans for (final Iterator iter = this.originals.iterator(); iter.hasNext();) { final EObject eObj = (EObject)iter.next(); if (eObj.eResource() != null) { originalsToProcess.add(eObj); } } // Find other objects to be deleted ... final Collection allDeleted = modelEditor.findOtherObjectsToBeDeleted(originalsToProcess, this.domain, additionalCommands, workspaceSearch); // Find references to objects being deleted ... modelEditor.findReferencesToObjectsBeingDeleted(allDeleted, this.domain, additionalCommands, workspaceSearch); // Add any new commands to the compound command ... for (final Iterator cmdIter = additionalCommands.iterator(); cmdIter.hasNext();) { append((Command)cmdIter.next()); } } protected ModelContents createAddCommandsForRelatedObjects() { if (this.additionalObjs.size() != 0) { final ContainerEditingDomain containerEdDomain = (ContainerEditingDomain)this.domain; //final ModelContents modelContents = containerEdDomain.getClipboardModelContents(true); final ModelContents modelContents = containerEdDomain.createClipboardModelContents(); // Make sure other commands don't set the actual clipboard contents, otherwise the // container editing domain will clear out the clipboard model contents. doCreateAdditionalCommands(modelContents); containerEdDomain.setClipboardMapping(new SelfKnowledgableCopyHelper() ); return modelContents; } return null; } /** * 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 ModelContents targetContents) { if (this.additionalObjs.isEmpty() ) { return this.additionalObjs; } // Find all of the annotations and transformations ... final Set annotations = new HashSet(); final Set mappingClassSets = new HashSet(); final Set transformations = new HashSet(); final List remaining = new ArrayList(); final Iterator iter = this.additionalObjs.iterator(); while (iter.hasNext()) { final Object additionalObj = iter.next(); if ( additionalObj instanceof Annotation ) { annotations.add(additionalObj); } else if ( additionalObj instanceof MappingClassSet ) { mappingClassSets.add(additionalObj); } else if ( additionalObj instanceof TransformationMappingRoot ) { transformations.add(additionalObj); } else { remaining.add(additionalObj); } } // Create the add 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(); createAndAppendAddCommand(annotations, container, feature); } // Create the add 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(); createAndAppendAddCommand(mappingClassSets, container, feature); } // Create the add 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(); createAndAppendAddCommand(transformations, container, feature); } return null; } protected void createAndAppendAddCommand(final Set objectsToAdd, final EObject container, final EStructuralFeature feature) { final Command addCommand = AddCommand.create(this.domain,container,feature,objectsToAdd); append(addCommand); } @Override public void execute() { // clear out all existing objects (including the ModelContents if one) ... this.domain.setClipboard(null); // execute the remove commands for the deleted/referenced objects super.execute(); // set the clipboard model contents if (this.clipboardModelContents != null && this.domain instanceof ContainerEditingDomain ) { final ContainerEditingDomain containerEdDomain = (ContainerEditingDomain) this.domain; final ModelContents existingContents = containerEdDomain.getClipboardModelContents(false); if (existingContents == null) { containerEdDomain.setClipboardModelContents(this.clipboardModelContents); } else if (existingContents != this.clipboardModelContents) { final String msg = ModelerCore.Util.getString("CutWithRelatedToClipboardCommand.Unexpected_existing_model_contents_on_clipboard"); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.WARNING,msg); containerEdDomain.setClipboardModelContents(this.clipboardModelContents); } } } public class SelfKnowledgableCopyHelper extends CopyCommand.Helper { /** */ private static final long serialVersionUID = 1L; /** * @see java.util.HashMap#get(java.lang.Object) */ public EObject get( EObject key ) { EObject result = super.get(key); if ( result == null ) { result = key; } return result; } /** * @see org.eclipse.emf.edit.command.CopyCommand.Helper#getCopy(org.eclipse.emf.ecore.EObject) */ @Override public EObject getCopy(EObject object) { EObject result = super.getCopy(object); if ( result == null ) { result = object; } return result; } } }