| //------------------------------------------------------------------------------ |
| // 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.EAnnotation; |
| import org.eclipse.emf.ecore.EModelElement; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| 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.Edge; |
| import org.eclipse.gmf.runtime.notation.Node; |
| import org.eclipse.uml2.uml.ActivityEdge; |
| import org.eclipse.uml2.uml.ActivityNode; |
| 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); |
| |
| // remove "inherted" mark, if there is any, on all edges of diagram copy |
| // |
| for (Object edge : diagramCopy.getEdges()) { |
| BridgeHelper.unmarkInHerited((Edge) edge); |
| } |
| |
| // 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<?> copyChildren = copy.getChildren(); |
| if(!copyChildren.isEmpty()) { |
| 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 = copyChildren.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(); |
| BridgeHelper.unmarkInHerited(node); |
| 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); |
| } |
| } |
| } |
| } |
| } |
| } else { |
| // there is situation where diagram notation does not have any children but its model does |
| // URIs to UMA element in the model elements still need to be updated |
| // |
| switch(diagramType) { |
| case IDiagramManager.ACTIVITY_DIAGRAM: |
| EObject diagramModel = copy.getElement(); |
| if(diagramModel instanceof org.eclipse.uml2.uml.Activity) { |
| org.eclipse.uml2.uml.Activity umlActivity = (org.eclipse.uml2.uml.Activity) diagramModel; |
| for (ActivityNode node : umlActivity.getNodes()) { |
| if(node instanceof StructuredActivityNode || node instanceof ActivityParameterNode) { |
| EModelElement modelElement = (EModelElement) node; |
| 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); |
| } |
| } |
| } |
| } |
| // remove any association to work order from edges |
| // |
| for (ActivityEdge edge : umlActivity.getEdges()) { |
| EAnnotation annotation = edge.getEAnnotation(BridgeHelper.UMA_ELEMENT); |
| if(annotation != null) { |
| EcoreUtil.remove(annotation); |
| } |
| } |
| } |
| } |
| } |
| switch(diagramType) { |
| case IDiagramManager.ACTIVITY_DIAGRAM: |
| EObject diagramModel = copy.getElement(); |
| if(diagramModel instanceof org.eclipse.uml2.uml.Activity) { |
| org.eclipse.uml2.uml.Activity umlActivity = (org.eclipse.uml2.uml.Activity) diagramModel; |
| // remove any association to work order from edges |
| // |
| for (ActivityEdge edge : umlActivity.getEdges()) { |
| EAnnotation annotation = edge.getEAnnotation(BridgeHelper.UMA_ELEMENT); |
| if(annotation != null) { |
| EcoreUtil.remove(annotation); |
| } |
| } |
| } |
| } |
| |
| } |
| |
| /* |
| * (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(); |
| } |
| } |