| //------------------------------------------------------------------------------ |
| // 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 implementation |
| //------------------------------------------------------------------------------ |
| package org.eclipse.epf.library.edit.process.command; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.emf.common.command.BasicCommandStack; |
| import org.eclipse.emf.common.command.Command; |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.xml.type.XMLTypePackage.Literals; |
| import org.eclipse.emf.edit.command.CommandParameter; |
| import org.eclipse.emf.edit.command.CopyCommand; |
| import org.eclipse.emf.edit.command.CreateCopyCommand; |
| import org.eclipse.emf.edit.command.InitializeCopyCommand; |
| import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; |
| import org.eclipse.emf.edit.provider.AdapterFactoryTreeIterator; |
| import org.eclipse.emf.edit.provider.ITreeItemContentProvider; |
| import org.eclipse.epf.library.edit.IConfigurator; |
| import org.eclipse.epf.library.edit.IFilter; |
| import org.eclipse.epf.library.edit.LibraryEditResources; |
| import org.eclipse.epf.library.edit.Providers; |
| import org.eclipse.epf.library.edit.TngAdapterFactory; |
| import org.eclipse.epf.library.edit.process.IBSItemProvider; |
| import org.eclipse.epf.library.edit.util.ConstraintManager; |
| import org.eclipse.epf.library.edit.util.ExtensionManager; |
| import org.eclipse.epf.library.edit.util.IDiagramManager; |
| import org.eclipse.epf.library.edit.util.ITextReferenceReplacer; |
| import org.eclipse.epf.library.edit.util.ProcessUtil; |
| import org.eclipse.epf.library.edit.util.Suppression; |
| import org.eclipse.epf.library.edit.util.TngUtil; |
| import org.eclipse.epf.uma.Activity; |
| import org.eclipse.epf.uma.Constraint; |
| import org.eclipse.epf.uma.Diagram; |
| import org.eclipse.epf.uma.MethodConfiguration; |
| import org.eclipse.epf.uma.MethodElement; |
| import org.eclipse.epf.uma.Process; |
| import org.eclipse.epf.uma.ProcessComponent; |
| import org.eclipse.epf.uma.ProcessPackage; |
| import org.eclipse.epf.uma.UmaFactory; |
| import org.eclipse.epf.uma.VariabilityElement; |
| import org.eclipse.epf.uma.VariabilityType; |
| import org.eclipse.epf.uma.edit.command.MethodElementInitializeCopyCommand; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * Physically copies an activity with all of its direct or inherited structural features and references. |
| * |
| * @author Phong Nguyen Le - Jun 21, 2006 |
| * @since 1.0 |
| */ |
| public class ActivityDeepCopyCommand extends CopyCommand { |
| private static final AdapterFactory[] adapterFactories = { |
| TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory(), |
| TngAdapterFactory.INSTANCE.getOBS_ComposedAdapterFactory(), |
| TngAdapterFactory.INSTANCE.getPBS_ComposedAdapterFactory() |
| }; |
| |
| private static final int[] diagramTypes = { |
| IDiagramManager.ACTIVITY_DETAIL_DIAGRAM, |
| IDiagramManager.ACTIVITY_DIAGRAM, |
| IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM |
| }; |
| |
| private class EditingDomain extends AdapterFactoryEditingDomain { |
| |
| /** |
| * @param adapterFactory |
| * @param commandStack |
| */ |
| public EditingDomain() { |
| super(TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory(), new BasicCommandStack()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain#createCommand(java.lang.Class, org.eclipse.emf.edit.command.CommandParameter) |
| */ |
| public Command createCommand(Class commandClass, CommandParameter commandParameter) { |
| if(commandClass == CreateCopyCommand.class) { |
| return new CreateDeepCopyCommand(this, commandParameter.getEOwner(), (Helper) commandParameter.getValue()); |
| } |
| if(commandClass == InitializeCopyCommand.class) { |
| return new InitializeDeepCopyCommand(this, commandParameter.getEOwner(), (Helper) commandParameter.getValue()); |
| } |
| return super.createCommand(commandClass, commandParameter); |
| } |
| } |
| |
| private static class CreateDeepCopyCommand extends CreateCopyCommand { |
| |
| /** |
| * @param domain |
| * @param owner |
| * @param copyHelper |
| */ |
| public CreateDeepCopyCommand(EditingDomain domain, EObject owner, Helper copyHelper) { |
| super(domain, owner, copyHelper); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.emf.edit.command.CreateCopyCommand#doGetChildrenToCopy() |
| */ |
| public Collection doGetChildrenToCopy() { |
| // Create commands to create copies of the children. |
| // |
| List result = new ArrayList(); |
| for (Iterator i = owner.eContents().iterator(); i.hasNext(); ) |
| { |
| Object o = i.next(); |
| if(o instanceof Activity) { |
| // make sure that Activity will be copied first |
| // so references to its inherited elements can be resolved properly |
| // |
| result.add(0, o); |
| } |
| else { |
| result.add(o); |
| } |
| } |
| return result; |
| |
| } |
| |
| } |
| |
| private class InitializeDeepCopyCommand extends MethodElementInitializeCopyCommand { |
| |
| /** |
| * @param domain |
| * @param owner |
| * @param copyHelper |
| */ |
| public InitializeDeepCopyCommand(EditingDomain domain, EObject owner, Helper copyHelper) { |
| super(domain, owner, copyHelper); |
| copy = (EObject) copyHelper.get(owner); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.epf.uma.edit.command.MethodElementInitializeCopyCommand#copyReferences() |
| */ |
| protected void copyReferences() { |
| Activity base = null; |
| Activity baseCopy = null; |
| Collection childBaseCopies = new HashSet(); |
| if(owner instanceof Activity) { |
| Activity activity = (Activity) owner; |
| if(ProcessUtil.isExtendingOrLocallyContributing(activity)) { |
| // copy inherited elements by deep-copying base activity |
| // |
| // deep copy of base activity at this point is essential so references to predecessors |
| // will be copied correctly |
| // |
| base = (Activity) activity.getVariabilityBasedOnElement(); |
| CopyHelper helper = (CopyHelper)copyHelper; |
| Activity oldBaseCopy = (Activity) helper.get(base); |
| // this will redirect any reference to copy of base in diagram to the copy of the activity |
| // |
| helper.putVariabilityElement(base, activity); |
| ArrayList childBases = new ArrayList(); |
| for (Iterator iter = activity.getBreakdownElements().iterator(); iter.hasNext();) { |
| Object e = iter.next(); |
| if(e instanceof VariabilityElement) { |
| VariabilityElement ve = (VariabilityElement) e; |
| VariabilityElement baseElement = ve.getVariabilityBasedOnElement(); |
| if(baseElement != null && |
| (ve.getVariabilityType() == VariabilityType.LOCAL_CONTRIBUTION_LITERAL || ve.getVariabilityType() == VariabilityType.LOCAL_REPLACEMENT_LITERAL)) |
| { |
| helper.putVariabilityElement(baseElement, ve); |
| childBases.add(baseElement); |
| } |
| } |
| } |
| |
| ActivityDeepCopyCommand cmd = new ActivityDeepCopyCommand(base, helper, config, targetProcess, monitor); |
| try { |
| cmd.execute(); |
| |
| baseCopy = (Activity) helper.get(base); |
| if(activity.getVariabilityType() == VariabilityType.EXTENDS_LITERAL) { |
| // keep activity only as backup copy of base |
| // |
| helper.removeVariabilityElement(base); |
| helper.putBackupCopy(base, activity); |
| |
| // put back oldBaseCopy |
| if(oldBaseCopy != null) { |
| helper.basicPut(base, oldBaseCopy); |
| } |
| } |
| |
| // remove the copies of all base since base copies are not added to the process |
| // |
| helper.remove(base); |
| for (Iterator iter = childBases.iterator(); iter.hasNext();) { |
| EObject childBaseCopy = (EObject) helper.remove(iter.next()); |
| childBaseCopies.add(childBaseCopy); |
| EcoreUtil.remove(childBaseCopy.eContainer()); |
| } |
| |
| Activity activityCopy = (Activity) copy; |
| |
| // remove the copies of base diagram if the activity already have diagram of the same type |
| // |
| for (int i = 0; i < diagramTypes.length; i++) { |
| int type = diagramTypes[i]; |
| if(diagramMgr.getDiagram(activity, type) != null) { |
| Diagram diagram = diagramMgr.getDiagram(activityCopy, type); |
| if(diagram != null) { |
| EcoreUtil.remove(diagram); |
| } |
| } |
| } |
| |
| // move content of base package over to the activity's package |
| // |
| moveContent(cmd.pkgCopy, activityCopy); |
| } |
| finally { |
| cmd.dispose(); |
| } |
| } |
| } |
| |
| super.copyReferences(); |
| |
| if(base != null) { |
| // copy inherited breakdown elements from the base activity in the right order |
| // |
| IConfigurator configurator = null; |
| MethodConfiguration currentConfig = null; |
| IFilter filter = ProcessUtil.getFilter(((AdapterFactoryEditingDomain)domain).getAdapterFactory()); |
| if(filter instanceof IConfigurator) { |
| configurator = (IConfigurator) filter; |
| currentConfig = configurator.getMethodConfiguration(); |
| configurator.setMethodConfiguration(config); |
| } |
| try { |
| Activity activity = (Activity) owner; |
| Activity activityCopy = ((Activity) copy); |
| |
| // Add breakdown elements from base copy to the activity copy. |
| // Don't add copy of base element of the existing children |
| // |
| List breakdownElements = new ArrayList(); |
| for (Iterator iter = baseCopy.getBreakdownElements().iterator(); iter.hasNext();) { |
| Object e = iter.next(); |
| if(!childBaseCopies.contains(e)) { |
| breakdownElements.add(e); |
| } |
| } |
| activityCopy.getBreakdownElements().addAll(0, breakdownElements); |
| EcoreUtil.remove(baseCopy); |
| |
| // copy other string attributes as well after realize them |
| // |
| for (Iterator iter = getAttributesToCopy().iterator(); iter.hasNext();) { |
| EAttribute attribute = (EAttribute) iter.next(); |
| Object value = Providers.getConfigurationApplicator().getAttribute(activity, attribute, config); |
| activityCopy.eSet(attribute, value); |
| } |
| |
| // copy presentation name |
| // |
| activityCopy.setPresentationName(ProcessUtil.getPresentationName(activity)); |
| |
| // clear the variability data |
| // |
| activityCopy.setVariabilityBasedOnElement(null); |
| activityCopy.setVariabilityType(null); |
| |
| // clear suppression data |
| // |
| Constraint rule = ConstraintManager.getConstraint(activityCopy, ConstraintManager.PROCESS_SUPPRESSION, false); |
| if(rule != null) { |
| EcoreUtil.remove(rule); |
| } |
| } |
| finally { |
| if(configurator != null) { |
| // restore current configruation |
| // |
| configurator.setMethodConfiguration(currentConfig); |
| } |
| } |
| } |
| } |
| } |
| |
| protected ProcessPackage pkgCopy; |
| protected MethodConfiguration config; |
| protected IDiagramManager diagramMgr; |
| |
| protected Process targetProcess; |
| |
| protected IProgressMonitor monitor; |
| |
| protected Activity activity; |
| |
| public ActivityDeepCopyCommand(Activity activity, CopyHelper copyHelper, MethodConfiguration config, Process targetProcess, IProgressMonitor monitor) { |
| super(null, activity.eContainer(), copyHelper); |
| Assert.isTrue(activity.eContainer() instanceof ProcessPackage, "Activity's container must be a ProcessPackage"); //$NON-NLS-1$ |
| domain = new EditingDomain(); |
| this.config = config; |
| this.targetProcess = targetProcess; |
| diagramMgr = ExtensionManager.getDiagramManager(); |
| Assert.isNotNull(diagramMgr, "Could not load diagram manager"); //$NON-NLS-1$ |
| this.monitor = monitor; |
| this.activity = activity; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.emf.edit.command.CopyCommand#execute() |
| */ |
| public void execute() { |
| monitor.subTask(NLS.bind(LibraryEditResources.copyingActivities_msg, ProcessUtil.getPresentationName(activity))); |
| super.execute(); |
| Collection result = super.getResult(); |
| if(!result.isEmpty()) { |
| pkgCopy = (ProcessPackage) result.iterator().next(); |
| fixProcessComponent(); |
| replaceTextReferences(); |
| } |
| } |
| |
| /** |
| * fix the process component to make it a process package. |
| * This method might be overriden by subclass to achive difference result. |
| * For example, |
| * @see org.eclipse.emf.edit.command.ProcessDeepCopyCommand#fixProcessComponent() |
| * |
| */ |
| protected void fixProcessComponent() { |
| if(pkgCopy instanceof ProcessComponent) { |
| // replace the ProcessComponent with a equivalent ProcessPackage |
| // |
| ProcessPackage pkg = UmaFactory.eINSTANCE.createProcessPackage(); |
| Collection features = new ArrayList(pkgCopy.eClass().getEAllStructuralFeatures()); |
| features.retainAll(pkg.eClass().getEAllStructuralFeatures()); |
| for (Iterator iter = features.iterator(); iter.hasNext();) { |
| EStructuralFeature feature = (EStructuralFeature) iter.next(); |
| Object value = pkgCopy.eGet(feature); |
| pkg.eSet(feature, value); |
| } |
| Process proc = ((ProcessComponent)pkgCopy).getProcess(); |
| if(proc != null) { |
| pkg.getProcessElements().add(0, proc); |
| } |
| pkgCopy = pkg; |
| } |
| } |
| |
| /** |
| * If textual descriptions in the copied elements contain references (URLs) to other elements |
| * within the same copied process then replace these references with references that point to |
| * the new elements in the copied structures. |
| */ |
| protected void replaceTextReferences() { |
| ITextReferenceReplacer txtRefReplacer = ExtensionManager.getTextReferenceReplacer(); |
| if(txtRefReplacer == null) return; |
| |
| Map oldToNewObjectMap = ((CopyHelper) copyHelper).getObjectToCopyMap(); |
| for (Iterator iter = pkgCopy.eAllContents(); iter.hasNext();) { |
| EObject element = (EObject) iter.next(); |
| for (Iterator attributes = element.eClass().getEAllAttributes().iterator(); attributes.hasNext(); ) |
| { |
| EAttribute attribute = (EAttribute) attributes.next(); |
| if (attribute.isChangeable() && !attribute.isDerived() && (attribute.isMany() || element.eIsSet(attribute)) |
| && attribute.getEAttributeType().getInstanceClass() == Literals.STRING.getInstanceClass()) |
| { |
| String text = (String) element.eGet(attribute); |
| if(text != null) { |
| text = txtRefReplacer.replace(text, targetProcess, oldToNewObjectMap); |
| element.eSet(attribute, text); |
| } |
| } |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.emf.common.command.CompoundCommand#getResult() |
| */ |
| public Collection getResult() { |
| if(pkgCopy != null) { |
| Activity act = ProcessUtil.findActivity(pkgCopy); |
| if(act != null) { |
| return Collections.singletonList(act); |
| } |
| } |
| return Collections.EMPTY_LIST; |
| } |
| |
| /** |
| * Moves content of source object <code>src</code> over to the target objec <code>target</code> |
| * @param src |
| * @param target |
| */ |
| private static void moveContent(ProcessPackage src, Activity act) { |
| ProcessPackage target = (ProcessPackage) act.eContainer(); |
| // move content of base package over to the activity's package |
| for (Iterator iter = new ArrayList(src.eContents()).iterator(); iter.hasNext();) { |
| EObject e = (EObject) iter.next(); |
| EStructuralFeature f = e.eContainingFeature(); |
| if(f.isMany()) { |
| ((List)target.eGet(f)).add(e); |
| } |
| } |
| if(src instanceof ProcessComponent) { |
| Process baseCopy = ((ProcessComponent)src).getProcess(); |
| target.getProcessElements().add(baseCopy); |
| } |
| |
| } |
| |
| public void copySuppressionStates() { |
| for (int i = 0; i < adapterFactories.length; i++) { |
| AdapterFactory adapterFactory = adapterFactories[i]; |
| Activity act = ProcessUtil.findActivity((ProcessPackage) owner); |
| ITreeItemContentProvider ip = (ITreeItemContentProvider) adapterFactory.adapt(act, ITreeItemContentProvider.class); |
| IBSItemProvider bsIp = (IBSItemProvider) ip; |
| Object top = bsIp.getTopItem(); |
| if(!(top instanceof Process) || !(((EObject)top).eContainer() instanceof ProcessComponent)) { |
| // item provider tree of the owner's process is not initialized yet |
| // |
| ProcessUtil.initializeItemProviderPath(act, adapterFactory); |
| } |
| Process proc = TngUtil.getOwningProcess(act); |
| Suppression suppression = Suppression.getSuppression(proc); |
| Iterator iter = new AdapterFactoryTreeIterator(adapterFactory, proc); |
| // for (Iterator iter = ip.getChildren(owner).iterator(); iter.hasNext();) { |
| while(iter.hasNext()) { |
| Object child = iter.next(); |
| Object e = TngUtil.unwrap(child); |
| MethodElement copy = (MethodElement) copyHelper.get(e); |
| |
| // copy suppression state, consider current process that inherits this element |
| // |
| if(copy != null && suppression.isSuppressed(child)) { |
| copy.setSuppressed(Boolean.TRUE); |
| } |
| } |
| } |
| } |
| } |