blob: 3429e84b047c2c66fce2d0fd4636c85b224ece57 [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 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);
}
}
}
}
}