blob: d2f42b8d419157af85fa736349cb7b108ec984c0 [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2005, 2007 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.diagram.core.commands;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.common.command.AbstractCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.epf.diagram.core.DiagramCorePlugin;
import org.eclipse.epf.diagram.core.bridge.BridgeHelper;
import org.eclipse.epf.diagram.core.services.DiagramHelper;
import org.eclipse.epf.diagram.core.services.DiagramManager;
import org.eclipse.epf.diagram.core.services.DiagramService;
import org.eclipse.epf.diagram.model.NamedNode;
import org.eclipse.epf.diagram.model.NodeContainer;
import org.eclipse.epf.diagram.model.util.TxUtil;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.command.IResourceAwareCommand;
import org.eclipse.epf.library.edit.process.BreakdownElementWrapperItemProvider;
import org.eclipse.epf.library.edit.process.command.CopyHelper;
import org.eclipse.epf.library.edit.util.ConfigurationSetter;
import org.eclipse.epf.library.edit.util.IDiagramManager;
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.BreakdownElement;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.Process;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.uml2.uml.ActivityParameterNode;
import org.eclipse.uml2.uml.ActivityPartition;
import org.eclipse.uml2.uml.StructuredActivityNode;
import com.ibm.icu.util.StringTokenizer;
/**
*
* Updates diagrams of the activity's deep copies.
*
* @author Phong Nguyen Le
* @since 1.2
*/
public class CopyDiagramForDeepCopyCommand extends AbstractCommand implements
IResourceAwareCommand {
private Collection<?> elements;
private Map<?,?> copyToOriginalMap;
private Collection<Diagram> copiedElements;
private static final boolean DEBUG = DiagramCorePlugin.getDefault()
.isDebugging();
private Process targetProcess;
private DiagramManager mgr;
private InternalTransactionalEditingDomain domain;
private CopyHelper copyHelper;
private MethodConfiguration config;
private Process srcProcess;
private HashMap<BreakdownElement, String> copyToWrapperPathMap;
public CopyDiagramForDeepCopyCommand(Collection<?> elements, Map<?, ?> copyToOriginalMap,
Process srcProcess, Process targetProcess, CopyHelper copyHelper,
MethodConfiguration config) {
this.copyHelper = copyHelper;
this.config = config;
this.srcProcess = srcProcess;
this.elements = elements;
this.copyToOriginalMap = copyToOriginalMap;
this.targetProcess = targetProcess;
// get diagram manager and domain
mgr = DiagramManager.getInstance(targetProcess, this);
domain = mgr.getEditingDomain();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.Command#execute()
*/
public void execute() {
try {
TxUtil.runInTransaction(domain, new Runnable() {
public void run() {
doExecute();
}
});
} catch (ExecutionException e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.Command#redo()
*/
public void redo() {
execute();
}
private void doExecute() {
if (copiedElements == null) {
copiedElements = new ArrayList<Diagram>();
} else {
copiedElements.clear();
}
copyToWrapperPathMap = new HashMap<BreakdownElement, String>();
if (copyHelper != null) {
for (Map.Entry<String, BreakdownElement> entry : copyHelper
.getWrapperPathToCopyMap().entrySet()) {
copyToWrapperPathMap.put(entry.getValue(), entry.getKey());
}
}
DiagramService diagramSvc = new DiagramService();
try {
for (Object e : elements) {
Object orig = copyToOriginalMap.get(e);
if (orig != null && orig instanceof Activity && e != null
&& e instanceof Activity) {
Activity copyActivity = (Activity) e;
Activity origActivity = (Activity) orig;
Collection<Diagram> diagrams = diagramSvc.getDiagrams(origActivity);
if (diagrams != null && !diagrams.isEmpty()) {
for (Diagram diagram : diagrams) {
if (diagram != null) {
// copy the diagram
Diagram diagramCopy = (Diagram) DiagramHelper
.copyDiagram(domain, diagram);
// update children references
updateReferences(diagramCopy, copyActivity, origActivity);
// associate with the activity
int diagramType = DiagramHelper
.getDiagramType(diagramCopy);
mgr.associate(diagramCopy, diagramType,
(Activity) copyActivity);
copiedElements.add(diagramCopy);
}
}
}
}
}
} catch (Exception ex) {
DiagramCorePlugin.getDefault().getLogger().logError(ex);
if (DEBUG) {
ex.printStackTrace();
}
} finally {
diagramSvc.dispose();
}
}
private void clearReadOnly(org.eclipse.epf.diagram.model.Node node) {
node.setReadOnly(false);
if (node instanceof NodeContainer) {
for (Iterator iter = ((NodeContainer)node).getNodes().iterator(); iter.hasNext();) {
org.eclipse.epf.diagram.model.Node child = (org.eclipse.epf.diagram.model.Node) iter.next();
child.setReadOnly(false);
}
}
}
private BreakdownElementWrapperItemProvider getOriginalWrapper(Activity copy) {
String wrapperPath = copyToWrapperPathMap.get(copy);
if(wrapperPath == null) {
return null;
}
if(srcProcess != null) {
Suppression suppression = Suppression.getSuppression(srcProcess);
AdapterFactory adapterFactory = TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory();
ConfigurationSetter configSetter = new ConfigurationSetter(adapterFactory);
try {
configSetter.set(config);
StringTokenizer tokens = new StringTokenizer(wrapperPath, "/"); //$NON-NLS-1$
ArrayList<String> guidList = new ArrayList<String>();
while(tokens.hasMoreTokens()) {
guidList.add(tokens.nextToken());
}
String[] guidPath = new String[guidList.size()];
guidList.toArray(guidPath);
Object o = suppression.getObjectByPath(guidPath, adapterFactory);
if(o instanceof BreakdownElementWrapperItemProvider) {
return (BreakdownElementWrapperItemProvider) o;
}
else {
System.out
.println("CopyDiagramCommand.getOriginalWrapper(): invalid wrapper for copy activity: " + o); //$NON-NLS-1$
}
}
finally {
configSetter.restore();
}
}
return null;
}
private Collection<BreakdownElement> getBreakdownElements(Activity origActivity, Activity copyActivity) {
BreakdownElementWrapperItemProvider wrapper = getOriginalWrapper(copyActivity);
Object object = wrapper != null ? wrapper : origActivity;
AdapterFactory adapterFactory = TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory();
ConfigurationSetter configSetter = new ConfigurationSetter(adapterFactory);
try {
configSetter.set(config);
ITreeItemContentProvider ip = (ITreeItemContentProvider) adapterFactory.adapt(object, ITreeItemContentProvider.class);
Collection<?> origChildren = ip.getChildren(origActivity);
Collection<BreakdownElement> elements = new ArrayList<BreakdownElement>();
for(Object origChild : origChildren) {
Object e = TngUtil.unwrap(origChild);
if(e instanceof BreakdownElement) {
elements.add((BreakdownElement) e);
}
}
return elements;
}
finally {
configSetter.restore();
}
}
private static BreakdownElement getBreakdownElement(Collection<BreakdownElement> elements, Activity base) {
for (BreakdownElement e : elements) {
if(e instanceof VariabilityElement) {
boolean found = false;
find_base:
for(VariabilityElement ve = (VariabilityElement) e; ve.getVariabilityBasedOnElement() != null; ve = ve.getVariabilityBasedOnElement()) {
if(ve.getVariabilityBasedOnElement() == base) {
found = true;
break find_base;
}
}
if(found) {
return (BreakdownElement) e;
}
}
}
return null;
}
private class CopyFinder {
private Activity origActivity;
private Activity copyActivity;
private Map<BreakdownElement, BreakdownElement> originalToCopyMap;
private Collection<BreakdownElement> elements;
private CopyFinder(Activity origActivity, Activity copyActivity) {
this.origActivity = origActivity;
this.copyActivity = copyActivity;
}
public Map<BreakdownElement, BreakdownElement> getOriginalToCopyMap() {
if(originalToCopyMap == null) {
originalToCopyMap = new HashMap<BreakdownElement, BreakdownElement>();
for (Iterator iterator = copyActivity.getBreakdownElements().iterator(); iterator.hasNext();) {
BreakdownElement e = (BreakdownElement) iterator.next();
BreakdownElement orig = (BreakdownElement) copyHelper.getOriginal(e);
originalToCopyMap.put(orig, e);
}
}
return originalToCopyMap;
}
BreakdownElement findCopy(BreakdownElement original) {
Object copy = getOriginalToCopyMap().get(original);
if(copy == null) {
if(original instanceof Activity) {
// me must be a base element of a local contributor or replacer
//
if(elements == null) {
elements = getBreakdownElements(origActivity, copyActivity);
}
copy = getBreakdownElement(elements, (Activity) original);
}
}
return (BreakdownElement) copy;
}
}
/**
* Update eAnnotations references
*
* @param copy
* @param origActivity
* @param copyActivity
*/
public void updateReferences(Diagram copy, Activity copyActivity, Activity origActivity) {
int diagramType = DiagramHelper.getDiagramType(copy);
CopyFinder copyFinder = new CopyFinder(origActivity, copyActivity);
List<Object> children = new ArrayList<Object>();
// collect all children first e.g. for ActivityPartition
// we don't have partition into partition so just getting one level sub-children
// are enough for now.
for (Iterator<?> itor = copy.getChildren().iterator(); itor.hasNext();) {
Node node = (Node) itor.next();
EObject obj = node.getElement();
children.add(node);
if (obj instanceof ActivityPartition){
children.addAll(node.getChildren());
}
}
for (Iterator<?> itor = children.iterator(); itor.hasNext();) {
Node node = (Node) itor.next();
EObject obj = node.getElement();
if (diagramType == IDiagramManager.ACTIVITY_DIAGRAM) {
if (obj instanceof StructuredActivityNode
|| obj instanceof ActivityParameterNode) {
EModelElement modelElement = (EModelElement) obj;
MethodElement me = BridgeHelper
.getMethodElementFromAnnotation(modelElement,
targetProcess.eResource().getResourceSet());
if(me instanceof BreakdownElement) {
BreakdownElement mappedMethodElement = copyFinder.findCopy((BreakdownElement) me);
if (mappedMethodElement != null) {
BridgeHelper.addEAnnotation(modelElement, mappedMethodElement);
}
}
}
} else if (diagramType == IDiagramManager.ACTIVITY_DETAIL_DIAGRAM) {
if(obj instanceof org.eclipse.epf.diagram.model.Node) {
clearReadOnly((org.eclipse.epf.diagram.model.Node)obj);
}
if (obj instanceof NodeContainer) {
NodeContainer nodeContainer = (NodeContainer) obj;
// do mapping for nodecontainer
MethodElement me = nodeContainer.getLinkedElement();
Object mappedMethodElement = null;
if(me instanceof BreakdownElement) {
mappedMethodElement = copyFinder.findCopy((BreakdownElement) me);
if (mappedMethodElement != null) {
nodeContainer
.setLinkedElement((MethodElement) mappedMethodElement);
}
}
// do mapping for its children
List<?> nodes = nodeContainer.getNodes();
for (int i = 0; i < nodes.size(); i++) {
NamedNode namedNode = (NamedNode) nodes.get(i);
me = namedNode.getLinkedElement();
if (me instanceof BreakdownElement) {
mappedMethodElement = copyFinder
.findCopy((BreakdownElement) me);
if (mappedMethodElement != null) {
namedNode
.setLinkedElement((MethodElement) mappedMethodElement);
}
}
}
}
} else if (diagramType == IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM) {
if(obj instanceof org.eclipse.epf.diagram.model.Node) {
clearReadOnly((org.eclipse.epf.diagram.model.Node)obj);
}
if (obj instanceof NamedNode) {
NamedNode namedNode = (NamedNode) obj;
MethodElement me = namedNode.getLinkedElement();
if (me instanceof BreakdownElement) {
Object mappedMethodElement = copyFinder.findCopy((BreakdownElement) me);
if (mappedMethodElement != null) {
namedNode
.setLinkedElement((MethodElement) mappedMethodElement);
}
}
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.AbstractCommand#prepare()
*/
protected boolean prepare() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.AbstractCommand#undo()
*/
public void undo() {
if (!(copiedElements == null || copiedElements.isEmpty())) {
try {
TxUtil.runInTransaction(domain, new Runnable() {
public void run() {
try {
for (Iterator iter = copiedElements.iterator(); iter.hasNext();) {
Diagram diagram = (Diagram) iter.next();
mgr.getResource().getContents()
.remove(diagram.getElement());
mgr.getResource().getContents().remove(diagram);
}
} catch (CoreException e) {
throw new WrappedException(e);
}
}
});
copiedElements.clear();
} catch (Exception ex) {
DiagramCorePlugin.getDefault().getLogger().logError(ex);
if (DEBUG) {
ex.printStackTrace();
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.epf.library.edit.command.IResourceAwareCommand#getModifiedResources()
*/
public Collection getModifiedResources() {
if (copiedElements == null || copiedElements.isEmpty()) {
// command is not executed yet
return Collections.EMPTY_LIST;
}
HashSet<Object> modifiedResources = new HashSet<Object>();
for (Iterator iter = copiedElements.iterator(); iter.hasNext();) {
Diagram diagram = (Diagram) iter.next();
if(diagram != null && diagram.eResource() != null)
modifiedResources.add(diagram.eResource());
}
return modifiedResources;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.AbstractCommand#dispose()
*/
public void dispose() {
if (mgr != null)
mgr.removeConsumer(this);
super.dispose();
}
}