| //------------------------------------------------------------------------------ |
| // 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.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.command.AbstractCommand; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.epf.library.edit.IConfigurationApplicator; |
| import org.eclipse.epf.library.edit.Providers; |
| import org.eclipse.epf.library.edit.category.ObjectLinkItemProvider; |
| import org.eclipse.epf.library.edit.command.IResourceAwareCommand; |
| import org.eclipse.epf.library.edit.ui.UserInteractionHelper; |
| import org.eclipse.epf.library.edit.util.ProcessUtil; |
| import org.eclipse.epf.library.edit.util.TngUtil; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.widgets.Display; |
| |
| import com.ibm.uma.Activity; |
| import com.ibm.uma.DescribableElement; |
| import com.ibm.uma.Descriptor; |
| import com.ibm.uma.MethodConfiguration; |
| import com.ibm.uma.MethodElement; |
| import com.ibm.uma.MethodPackage; |
| import com.ibm.uma.MethodPlugin; |
| import com.ibm.uma.Process; |
| import com.ibm.uma.Role; |
| import com.ibm.uma.RoleDescriptor; |
| import com.ibm.uma.Task; |
| import com.ibm.uma.TaskDescriptor; |
| import com.ibm.uma.UmaPackage; |
| import com.ibm.uma.WorkProductDescriptor; |
| |
| /** |
| * Abstract base DropCommand class for breakdown structure editor |
| * |
| * @author Phong Nguyen Le |
| * @since 1.0 |
| */ |
| public abstract class BSDropCommand extends AbstractCommand implements |
| IResourceAwareCommand { |
| |
| protected Activity activity; |
| |
| protected List dropElements; |
| |
| private Set modifiedResources; |
| |
| protected List elementsToAddToDefaultConfig; |
| |
| private HashSet addedObjects; |
| |
| private Process process; |
| |
| private boolean addedToDefaultConfig = false; |
| |
| protected boolean synchronize = false; |
| |
| protected ArrayList taskDescList; |
| |
| protected ArrayList taskDescriptorsToUpdate; |
| |
| protected Set descriptorsToRefresh; |
| |
| /** |
| * Map of descriptor to old refreshable feature map |
| */ |
| private Map descriptorToOldRefreshableFeaturesMap; |
| |
| /** |
| * Map of descriptor to map of feature to new values |
| */ |
| protected Map descriptorToNewFeatureValuesMap; |
| |
| private HashMap wpdToOldResponsibleRoleMap; |
| |
| /** |
| * Map of TaskDescriptor to list of newly added steps |
| */ |
| private Map taskDescToNewStepsMap; |
| |
| private HashMap descriptorToOldFeatureValuesMap; |
| |
| protected boolean canceled; |
| |
| private MethodConfiguration config; |
| |
| private List synchFeatures; |
| |
| /** |
| * @param activity |
| * the activity that the given elements are dropped on |
| * @param dropElements |
| * the elements to drop on the given activity |
| */ |
| public BSDropCommand(Activity activity, List dropElements) { |
| super(); |
| this.activity = activity; |
| process = TngUtil.getOwningProcess(activity); |
| this.dropElements = new ArrayList(); |
| for (Iterator iter = dropElements.iterator(); iter.hasNext();) { |
| Object element = TngUtil.unwrap(iter.next()); |
| if (element instanceof ObjectLinkItemProvider) { |
| element = ((ObjectLinkItemProvider) element).getTarget(); |
| } |
| if (!this.dropElements.contains(element) |
| && !(element instanceof EObject && ((EObject) element) |
| .eIsProxy())) { |
| this.dropElements.add(element); |
| } |
| } |
| } |
| |
| /** |
| * @param synch |
| * if true, the command will clean the content and relationships |
| * of existing descriptors and refresh them with the linked |
| * MethodElement |
| */ |
| public BSDropCommand(Activity activity, List dropElements, boolean synch) { |
| this(activity, dropElements); |
| this.synchronize = synch; |
| } |
| |
| /** |
| * Synchronize the given content elements to its TaskDescriptors in the |
| * given activity using the given MethodConfiguration and list of |
| * synchronizable features. |
| * |
| * @param activity |
| * @param dropElements |
| * the elements to synchronize |
| * @param config |
| * @param synchFeatures |
| * the synchronizable features |
| */ |
| public BSDropCommand(Activity activity, List dropElements, |
| MethodConfiguration config, List synchFeatures) { |
| this(activity, dropElements, true); |
| this.config = config; |
| this.synchFeatures = synchFeatures; |
| } |
| |
| public MethodConfiguration getMethodConfiguration() { |
| if (config == null) { |
| config = TngUtil.getOwningProcess(activity).getDefaultContext(); |
| } |
| return config; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.common.command.AbstractCommand#dispose() |
| */ |
| public void dispose() { |
| if (dropElements != null) { |
| dropElements.clear(); |
| } |
| if (modifiedResources != null) { |
| modifiedResources.clear(); |
| } |
| if (elementsToAddToDefaultConfig != null) { |
| elementsToAddToDefaultConfig.clear(); |
| } |
| if (addedObjects != null) { |
| addedObjects.clear(); |
| } |
| if (descriptorToOldRefreshableFeaturesMap != null) { |
| descriptorToOldRefreshableFeaturesMap.clear(); |
| } |
| if (taskDescList != null) { |
| taskDescList.clear(); |
| } |
| if (taskDescToNewStepsMap != null) { |
| taskDescToNewStepsMap.clear(); |
| } |
| if (wpdToOldResponsibleRoleMap != null) { |
| wpdToOldResponsibleRoleMap.clear(); |
| } |
| if (taskDescriptorsToUpdate != null) { |
| taskDescriptorsToUpdate.clear(); |
| } |
| if (descriptorsToRefresh != null) { |
| descriptorsToRefresh.clear(); |
| } |
| activity = process = null; |
| super.dispose(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see com.ibm.library.edit.command.IResourceAwareCommand#getModifiedResources() |
| */ |
| public Collection getModifiedResources() { |
| if (modifiedResources == null) { |
| modifiedResources = new HashSet(); |
| if (activity.eResource() != null) { |
| modifiedResources.add(activity.eResource()); |
| } |
| } |
| return modifiedResources; |
| } |
| |
| /** |
| * Clears all the refreshable features of the given descriptor |
| * |
| * @param descriptor |
| */ |
| private boolean clearDescriptor(Descriptor descriptor) { |
| boolean ret = ProcessUtil.clearDescriptor(descriptor, |
| descriptorToOldRefreshableFeaturesMap); |
| if (ret && descriptor instanceof TaskDescriptor) { |
| if (taskDescriptorsToUpdate == null) { |
| taskDescriptorsToUpdate = new ArrayList(); |
| } |
| taskDescriptorsToUpdate.add(descriptor); |
| } |
| return ret; |
| } |
| |
| protected boolean preExecute() { |
| boolean b = !dropElements.isEmpty(); |
| if (b) { |
| descriptorToNewFeatureValuesMap = new HashMap(); |
| |
| if (synchronize) { |
| descriptorsToRefresh = new HashSet(); |
| } |
| } |
| return b; |
| } |
| |
| /** |
| * Checks and adds elements to the default configuration |
| * |
| * @return false if user canceled the operation |
| */ |
| private boolean addToDefaultConfiguration() { |
| if (elementsToAddToDefaultConfig == null) { |
| elementsToAddToDefaultConfig = new ArrayList(); |
| for (Iterator iter = dropElements.iterator(); iter.hasNext();) { |
| Object element = iter.next(); |
| switch (UserInteractionHelper.checkAgainstDefaultConfiguration( |
| process, element)) { |
| case 0: |
| iter.remove(); |
| break; |
| case 2: |
| elementsToAddToDefaultConfig.add(element); |
| break; |
| case -1: |
| return false; |
| } |
| } |
| if (!elementsToAddToDefaultConfig.isEmpty()) { |
| addedObjects = new HashSet(); |
| for (Iterator iter = elementsToAddToDefaultConfig.iterator(); iter |
| .hasNext();) { |
| EObject element = (EObject) iter.next(); |
| ProcessUtil.addToDefaultConfiguration(process, element, |
| addedObjects); |
| } |
| if (!addedObjects.isEmpty()) { |
| getModifiedResources().add( |
| process.getDefaultContext().eResource()); |
| } |
| addedToDefaultConfig = true; |
| } |
| } |
| return true; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.common.command.Command#execute() |
| */ |
| public void execute() { |
| // BusyIndicator.showWhile(Display.getCurrent(), new Runnable() { |
| // |
| // public void run() { |
| // canceled = !addToDefaultConfiguration(); |
| // } |
| // |
| // }); |
| // |
| // //TODO: This caused NullPointerException or ThreadAccessError when |
| // showing selection dialog is needed |
| // // |
| // IRunnableWithProgress runnable = new IRunnableWithProgress() { |
| // |
| // public void run(IProgressMonitor monitor) throws |
| // InvocationTargetException, InterruptedException { |
| // canceled = !preExecute(); |
| // } |
| // |
| // }; |
| // UserInteractionHelper.runWithProgress(runnable, null); |
| // |
| // if(!canceled) { |
| // BusyIndicator.showWhile(Display.getCurrent(), new Runnable() { |
| // |
| // public void run() { |
| // redo(); |
| // } |
| // |
| // }); |
| // } |
| |
| BusyIndicator.showWhile(Display.getCurrent(), new Runnable() { |
| |
| public void run() { |
| if (addToDefaultConfiguration() && preExecute()) { |
| redo(); |
| } |
| } |
| |
| }); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.common.command.Command#redo() |
| */ |
| public void redo() { |
| // add elements to the default configuration if needed |
| // |
| if (!addedToDefaultConfig) { |
| addToDefaultConfiguration(); |
| } |
| |
| updateDescriptors(); |
| doExecute(); |
| |
| } |
| |
| /** |
| * Updates descriptors |
| */ |
| private void updateDescriptors() { |
| if (synchronize) { |
| clearDescriptors(); |
| } |
| |
| for (Iterator iter = descriptorToNewFeatureValuesMap.entrySet() |
| .iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| Descriptor desc = (Descriptor) entry.getKey(); |
| Map featureMap = (Map) entry.getValue(); |
| for (Iterator iterator = featureMap.entrySet().iterator(); iterator |
| .hasNext();) { |
| entry = (Map.Entry) iterator.next(); |
| EStructuralFeature feature = (EStructuralFeature) entry |
| .getKey(); |
| if (feature.isMany()) { |
| if (((List) desc.eGet(feature)).addAll((Collection) entry |
| .getValue())) { |
| System.out |
| .println("BSDropCommand.updateDescriptors(): changed"); |
| System.out.println(" descriptor: " + desc); |
| System.out.println(" feature: " + feature); |
| } |
| } else { |
| Object oldValue = desc.eGet(feature); |
| if (oldValue != entry.getValue()) { |
| saveOldFeatureValue(desc, feature, oldValue); |
| desc.eSet(feature, entry.getValue()); |
| System.out |
| .println("BSDropCommand.updateDescriptors(): changed"); |
| System.out.println(" descriptor: " + desc); |
| System.out.println(" feature: " + feature); |
| } |
| } |
| } |
| } |
| |
| if (synchronize) { |
| // refresh name, presentation name of descriptors with the value |
| // from associated content element |
| // |
| for (Iterator iter = descriptorsToRefresh.iterator(); iter |
| .hasNext();) { |
| Descriptor descriptor = (Descriptor) iter.next(); |
| MethodElement e = ProcessUtil.getAssociatedElement(descriptor); |
| if (!descriptor.getName().equals(e.getName())) { |
| saveOldFeatureValue(descriptor, UmaPackage.eINSTANCE |
| .getNamedElement_Name(), descriptor.getName()); |
| descriptor.setName(e.getName()); |
| System.out |
| .println("BSDropCommand.updateDescriptors(): name changed " |
| + descriptor); |
| } |
| if (e instanceof DescribableElement) { |
| String presName = ((DescribableElement) e) |
| .getPresentationName(); |
| if (!presName.equals(descriptor.getPresentationName())) { |
| saveOldFeatureValue(descriptor, UmaPackage.eINSTANCE |
| .getDescribableElement_PresentationName(), |
| descriptor.getPresentationName()); |
| descriptor.setPresentationName(presName); |
| System.out |
| .println("BSDropCommand.updateDescriptors(): presentation name changed " |
| + descriptor); |
| } |
| } |
| } |
| } |
| |
| updateTaskDescriptors(); |
| |
| setResponsibleRole(); |
| } |
| |
| /** |
| * @param desc |
| * @param feature |
| * @param value |
| */ |
| private void saveOldFeatureValue(Descriptor desc, |
| EStructuralFeature feature, Object value) { |
| if (descriptorToOldFeatureValuesMap == null) { |
| descriptorToOldFeatureValuesMap = new HashMap(); |
| } |
| Map featureMap = (Map) descriptorToOldFeatureValuesMap.get(desc); |
| if (featureMap == null) { |
| featureMap = new HashMap(); |
| descriptorToOldFeatureValuesMap.put(desc, featureMap); |
| } |
| featureMap.put(feature, value); |
| } |
| |
| private void undoUpdateDescriptors() { |
| undoSetResponsibleRole(); |
| |
| undoUpdateTaskDescriptors(); |
| |
| if (descriptorToNewFeatureValuesMap != null) { |
| for (Iterator iter = descriptorToNewFeatureValuesMap.entrySet() |
| .iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| Descriptor desc = (Descriptor) entry.getKey(); |
| Map featureMap = (Map) entry.getValue(); |
| for (Iterator iterator = featureMap.entrySet().iterator(); iterator |
| .hasNext();) { |
| entry = (Map.Entry) iterator.next(); |
| EStructuralFeature feature = (EStructuralFeature) entry |
| .getKey(); |
| if (feature.isMany()) { |
| ((List) desc.eGet(feature)) |
| .removeAll((Collection) entry.getValue()); |
| } |
| } |
| } |
| } |
| |
| // restore single-value feature |
| // |
| if (descriptorToOldFeatureValuesMap != null) { |
| for (Iterator iter = descriptorToOldFeatureValuesMap.entrySet() |
| .iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| Descriptor desc = (Descriptor) entry.getKey(); |
| Map featureMap = (Map) entry.getValue(); |
| for (Iterator iterator = featureMap.entrySet().iterator(); iterator |
| .hasNext();) { |
| entry = (Map.Entry) iterator.next(); |
| EStructuralFeature feature = (EStructuralFeature) entry |
| .getKey(); |
| desc.eSet(feature, entry.getValue()); |
| } |
| } |
| } |
| |
| // restore value for refreshable features that had been cleared |
| // |
| if (synchronize) { |
| undoClearDescriptors(); |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void clearDescriptors() { |
| if (descriptorToOldRefreshableFeaturesMap == null) { |
| descriptorToOldRefreshableFeaturesMap = new HashMap(); |
| if (!descriptorsToRefresh.isEmpty()) { |
| for (Iterator iter = descriptorsToRefresh.iterator(); iter |
| .hasNext();) { |
| clearDescriptor((Descriptor) iter.next()); |
| } |
| // descriptorsToRefresh.clear(); |
| } |
| } |
| } |
| |
| /** |
| * Updates affected task descriptors with new data from method content |
| */ |
| private void updateTaskDescriptors() { |
| if (taskDescriptorsToUpdate != null) { |
| if (taskDescToNewStepsMap == null) { |
| taskDescToNewStepsMap = new HashMap(); |
| } |
| IConfigurationApplicator configApplicator = Providers |
| .getConfigurationApplicator(); |
| for (Iterator iter = taskDescriptorsToUpdate.iterator(); iter |
| .hasNext();) { |
| TaskDescriptor taskDesc = (TaskDescriptor) iter.next(); |
| Task task = taskDesc.getTask(); |
| if (task != null && !((EObject) task).eIsProxy()) { |
| List steps = (List) configApplicator.getReference(task |
| .getPresentation(), UmaPackage.eINSTANCE |
| .getContentDescription_Sections(), config); |
| |
| // add those steps to TaskDescriptor if they are not there |
| // yet. |
| // |
| ArrayList newSteps = new ArrayList(); |
| taskDesc.getSelectedSteps().retainAll(steps); |
| for (Iterator iter1 = steps.iterator(); iter1.hasNext();) { |
| Object step = iter1.next(); |
| if (!taskDesc.getSelectedSteps().contains(step)) { |
| newSteps.add(step); |
| } |
| } |
| if (!newSteps.isEmpty()) { |
| taskDesc.getSelectedSteps().addAll(newSteps); |
| taskDescToNewStepsMap.put(taskDesc, newSteps); |
| System.out |
| .println("BSDropCommand.updateTaskDescriptors(): changed"); |
| } |
| } |
| } |
| } |
| } |
| |
| private void undoUpdateTaskDescriptors() { |
| if (taskDescToNewStepsMap != null) { |
| for (Iterator iter = taskDescToNewStepsMap.entrySet().iterator(); iter |
| .hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| TaskDescriptor taskDesc = (TaskDescriptor) entry.getKey(); |
| taskDesc.getSelectedSteps().removeAll( |
| (Collection) entry.getValue()); |
| } |
| } |
| } |
| |
| /** |
| * Go thru all the work product descriptors of this activity and set the |
| * responsible role for them if there is any |
| */ |
| private void setResponsibleRole() { |
| if (wpdToOldResponsibleRoleMap == null) { |
| wpdToOldResponsibleRoleMap = new HashMap(); |
| } |
| |
| List brElements = activity.getBreakdownElements(); |
| List wpDescList = new ArrayList(); |
| List roleDescriptors = new ArrayList(); |
| for (Iterator itor = brElements.iterator(); itor.hasNext();) { |
| Object obj = itor.next(); |
| if (obj instanceof WorkProductDescriptor) { |
| wpDescList.add(obj); |
| } else if (obj instanceof RoleDescriptor) { |
| roleDescriptors.add(obj); |
| } |
| } |
| |
| for (Iterator itor = roleDescriptors.iterator(); itor.hasNext();) { |
| RoleDescriptor roleDesc = (RoleDescriptor) itor.next(); |
| Role role = roleDesc.getRole(); |
| if (role != null) { |
| List responsibleWorkProducts = role.getResponsibleFor(); |
| |
| for (int j = wpDescList.size() - 1; j > -1; j--) { |
| WorkProductDescriptor wpDesc = (WorkProductDescriptor) wpDescList |
| .get(j); |
| if (responsibleWorkProducts.contains(wpDesc |
| .getWorkProduct()) |
| && wpDesc.getResponsibleRole() != roleDesc) { |
| wpdToOldResponsibleRoleMap.put(wpDesc, wpDesc |
| .getResponsibleRole()); |
| wpDesc.setResponsibleRole(roleDesc); |
| System.out |
| .println("BSDropCommand.setResponsibleRole(): changed"); |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.common.command.AbstractCommand#undo() |
| */ |
| public void undo() { |
| // remove any object that had been added to the default configuration |
| // |
| if (addedObjects != null && !addedObjects.isEmpty()) { |
| MethodConfiguration config = process.getDefaultContext(); |
| for (Iterator iter = addedObjects.iterator(); iter.hasNext();) { |
| Object element = iter.next(); |
| if (element instanceof MethodPlugin) { |
| config.getMethodPluginSelection().remove(element); |
| } else if (element instanceof MethodPackage) { |
| config.getMethodPackageSelection().remove(element); |
| } |
| } |
| addedToDefaultConfig = false; |
| } |
| |
| undoUpdateDescriptors(); |
| |
| doUndo(); |
| } |
| |
| /** |
| * |
| */ |
| private void undoClearDescriptors() { |
| for (Iterator iter = descriptorToOldRefreshableFeaturesMap.entrySet() |
| .iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| Descriptor desc = (Descriptor) entry.getKey(); |
| Map featureMap = (Map) entry.getValue(); |
| for (Iterator iterator = featureMap.entrySet().iterator(); iterator |
| .hasNext();) { |
| entry = (Map.Entry) iterator.next(); |
| desc |
| .eSet((EStructuralFeature) entry.getKey(), entry |
| .getValue()); |
| } |
| } |
| } |
| |
| /** |
| * Undoes the change made by |
| * {@link #setResponsibleRole() setResponsibleRole() } |
| */ |
| private void undoSetResponsibleRole() { |
| for (Iterator iter = wpdToOldResponsibleRoleMap.entrySet().iterator(); iter |
| .hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| WorkProductDescriptor wpd = (WorkProductDescriptor) entry.getKey(); |
| wpd.setResponsibleRole((RoleDescriptor) entry.getValue()); |
| } |
| } |
| |
| protected boolean prepare() { |
| return true; |
| } |
| |
| protected abstract void doExecute(); |
| |
| protected abstract void doUndo(); |
| |
| public static interface IExecutor { |
| boolean preExecute(); |
| |
| void doExcecute(); |
| |
| void doUndo(); |
| } |
| |
| } |