blob: 3d2b46f7e2b946d135be847021ed5dd7820ad5e6 [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.util;
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 java.util.Set;
import org.eclipse.emf.common.command.AbstractCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.provider.AdapterFactoryTreeIterator;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.emf.edit.provider.WrapperItemProvider;
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.TngAdapterFactory;
import org.eclipse.epf.library.edit.command.IResourceAwareCommand;
import org.eclipse.epf.library.edit.process.BSActivityItemProvider;
import org.eclipse.epf.library.edit.process.BreakdownElementWrapperItemProvider;
import org.eclipse.epf.library.edit.process.IBSItemProvider;
import org.eclipse.epf.library.edit.process.command.RemoveUnusedDescriptorsCommand;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.Artifact;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.Constraint;
import org.eclipse.epf.uma.Descriptor;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.Process;
import org.eclipse.epf.uma.RoleDescriptor;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.TeamProfile;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.VariabilityType;
import org.eclipse.epf.uma.WorkBreakdownElement;
import org.eclipse.epf.uma.WorkProduct;
import org.eclipse.epf.uma.WorkProductDescriptor;
import org.eclipse.epf.uma.ecore.impl.MultiResourceEObject;
import org.eclipse.epf.uma.ecore.util.OppositeFeature;
import org.eclipse.epf.uma.util.AssociationHelper;
import org.eclipse.epf.uma.util.UmaUtil;
import com.ibm.icu.util.StringTokenizer;
/**
* @author Phong Nguyen Le - Aug 9, 2005
* @since 1.0
*/
public class Suppression {
public static final String WBS = "wbs"; //$NON-NLS-1$
private static final String TBS = "tbs"; //$NON-NLS-1$
private static final String WPBS = "wpbs"; //$NON-NLS-1$
private static final String CBS = "cbs"; //$NON-NLS-1$
private static final Map procToSuppressionMap = new HashMap();
private static boolean autoInheritIntermediateSuppressionState = true;
private Process process;
private Set suppressedExternalElementPaths;
private boolean modified;
private Set internalUnsuppressedElements = new HashSet();
public static final void clearCachedSuppressions() {
procToSuppressionMap.clear();
}
/**
* Removes suppressions of invalid processes
*/
public static final void cleanUp() {
ArrayList listToRemove = new ArrayList();
for (Iterator iter = new ArrayList(procToSuppressionMap.keySet()).iterator(); iter.hasNext();) {
Process proc = (Process) iter.next();
if(proc.eIsProxy()) {
listToRemove.add(proc);
}
}
int size = listToRemove.size();
for (int i = 0; i < size; i++) {
procToSuppressionMap.remove(listToRemove.get(i));
}
}
public static final void setAutoInheritSuppressionStates(boolean b) {
autoInheritIntermediateSuppressionState = b;
}
public Suppression(Process process) {
this.process = process;
suppressedExternalElementPaths = loadSuppressedElementPaths();
}
public Process getProcess() {
return process;
}
private Set loadSuppressedElementPaths() {
Constraint rule = ConstraintManager.getConstraint(process,
ConstraintManager.PROCESS_SUPPRESSION, false); // (Constraint)
// process.getOwnedRules().get(0);
if (rule != null && rule.getBody().length() > 0) {
Set paths = new HashSet();
for (StringTokenizer tokens = new StringTokenizer(rule.getBody()); tokens
.hasMoreTokens();) {
paths.add(tokens.nextToken());
}
return paths;
}
return null;
}
private Set getSuppressedExternalElementPaths() {
if (suppressedExternalElementPaths == null) {
suppressedExternalElementPaths = loadSuppressedElementPaths();
if (suppressedExternalElementPaths == null) {
suppressedExternalElementPaths = new HashSet();
}
}
return suppressedExternalElementPaths;
}
/**
* @param process
* @param selection
* @return
*/
public boolean hasSuppressed(Collection selection) {
for (Iterator iter = selection.iterator(); iter.hasNext();) {
Object element = iter.next();
if (element instanceof BreakdownElementWrapperItemProvider) {
if (isSuppressed((BreakdownElementWrapperItemProvider) element)) {
return true;
}
} else if (element instanceof BreakdownElement) {
if (isSuppressed((BreakdownElement) element)) {
return true;
}
}
}
return false;
}
/**
* Checks if the given selection has any element that is not suppressed yet
* in this suppression's process
*
* @param selection
* @return
*/
public boolean canSuppress(Collection selection) {
return canDo(selection, true);
}
/**
* Checks if the given selection has any element that is suppressed in this
* suppression's process
*
* @param selection
* @return
*/
public boolean canReveal(Collection selection) {
return canDo(selection, false);
}
/**
* Extracts items from the given selection that can be suppressed/revealed
* (depending on the <code>suppressed</code> parameter)
*
* @param selection
* @param suppressed
* @return
*/
private Collection getApplicableItems(Collection selection,
boolean suppressed) {
ArrayList applicableItems = new ArrayList();
for (Iterator iter = selection.iterator(); iter.hasNext();) {
Object element = iter.next();
if (element instanceof BreakdownElementWrapperItemProvider) {
BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) element;
if (wrapper.isReadOnly()) {
if (isInSuppressedList(wrapper) != suppressed) {
applicableItems.add(element);
}
} else {
Object e = TngUtil.unwrap(wrapper);
if (e instanceof MethodElement
&& ((MethodElement) e).getSuppressed()
.booleanValue() != suppressed) {
applicableItems.add(element);
}
}
} else if (element instanceof MethodElement) {
if (((MethodElement) element).getSuppressed().booleanValue() != suppressed) {
applicableItems.add(element);
}
}
}
return applicableItems;
}
/**
* Checks if the given element is valid to suppress/reveal upon
* @param element
* @return
*/
public static boolean isValid(Object element) {
// don't show suppress/reveal for roledescriptor under team, work product descriptor under deliverable work product,
// and rolled-up item
//
BreakdownElement obj = null;
if (element instanceof BreakdownElementWrapperItemProvider) {
BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) element;
if(wrapper.isRollupChild()) {
return false;
}
obj = (BreakdownElement) TngUtil.unwrap(wrapper);
}
else if (element instanceof BreakdownElement)
obj = (BreakdownElement) element;
if (obj instanceof RoleDescriptor || obj instanceof WorkProductDescriptor) {
if (obj.getSuperActivities() == null
|| obj.getSuperActivities() == null) {
return false;
}
}
return true;
}
/**
* Checks if the given selection has any item that can be
* suppressed/revealed (depending on the <code>suppressed</code>
* parameter)
*
* @param selection
* @param suppressed
* @return
*/
private boolean canDo(Collection selection, boolean suppressed) {
for (Iterator iter = selection.iterator(); iter.hasNext();) {
Object element = iter.next();
if(isValid(element)) {
if (element instanceof BreakdownElementWrapperItemProvider) {
BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) element;
if (wrapper.isReadOnly()) {
if (isInSuppressedList(wrapper) != suppressed) {
return true;
}
} else {
Object e = TngUtil.unwrap(wrapper);
if (e instanceof MethodElement &&
((MethodElement) e).getSuppressed().booleanValue() != suppressed) {
}
}
} else if (element instanceof MethodElement) {
if (((MethodElement) element).getSuppressed().booleanValue() != suppressed) {
return true;
}
}
}
}
return false;
}
/**
* A breakdown element is suppressed if itself or any of its parent activity
* is suppressed
*
* @param e
* @return
*/
private boolean __isSuppressed(BreakdownElement e) {
return getSuppressed(e, true, null) != null;
}
private static boolean isDirectlySuppressed(MethodElement e) {
Boolean b = e.getSuppressed();
if (b != null && b.booleanValue()) {
return true;
}
if (e instanceof VariabilityElement) {
VariabilityElement ve = (VariabilityElement) e;
VariabilityType variabilityType = ve.getVariabilityType();
if (variabilityType == VariabilityType.EXTENDS_LITERAL
|| variabilityType == VariabilityType.CONTRIBUTES_LITERAL) {
if (ve.getVariabilityBasedOnElement() != null) {
return isDirectlySuppressed(ve
.getVariabilityBasedOnElement());
}
}
}
return false;
}
/**
* Gets the suppressed breakdown element that made the given breakdown
* element become suppressed. This method will check the suppression state of the parent upto the specified
* <code>top</code> only if <code>checkParent</code> is <code>true</code>. It will not check the suppression state of
* <code>top</code>
* @param e
* @return
*/
private static BreakdownElement getSuppressed(BreakdownElement e, boolean checkParent, Object top) {
if (e.getSuppressed().booleanValue()) {
return e;
}
if(checkParent) {
for (BreakdownElement be = e; be != top && be.getSuperActivities() != null;) {
be = be.getSuperActivities();
if (be.getSuppressed().booleanValue()) {
return be;
}
}
// special handling for nested artifact descriptors and deliverable parts
//
if (e instanceof WorkProductDescriptor) {
WorkProductDescriptor wpDesc = ((WorkProductDescriptor)e);
WorkProduct wp = wpDesc.getWorkProduct();
if (wp instanceof Artifact) {
// look for parent artifact descriptor in the same activity
// and check their suppression state
//
Activity act = UmaUtil.getParentActivity(e);
if (act != null) {
for (Iterator iter = act.getBreakdownElements().iterator(); iter
.hasNext();) {
Object element = iter.next();
if (element != e
&& element instanceof WorkProductDescriptor) {
WorkProductDescriptor wpd = ((WorkProductDescriptor) element);
WorkProduct otherWp = wpd.getWorkProduct();
if (otherWp instanceof Artifact
&& UmaUtil.isContainedBy(wp, otherWp)
&& wpd.getSuppressed().booleanValue()) {
return wpd;
}
}
}
}
}
if(wpDesc != top && wpDesc.getSuperActivities() == null) {
List list = AssociationHelper.getDeliverableDescriptors(wpDesc);
if(list.size() == 1) {
// this work product descriptor is a deliverable part of a deliverable work product descriptor
// check the suppression state of the deliverable work product descriptor
//
return getSuppressed((BreakdownElement) list.get(0), checkParent, top);
}
}
}
// special handling for team profile own role descriptor
//
else if (e instanceof RoleDescriptor) {
if (e.getSuperActivities() == null) {
List list = AssociationHelper.getTeamProfiles((RoleDescriptor) e);
if (list.size() == 1) {
TeamProfile team = (TeamProfile) list.get(0);
if(team != top && team != null) {
return getSuppressed(team, checkParent, top);
}
}
}
}
// special handling for sub team profile
//
else if (e instanceof TeamProfile) {
if (e.getSuperActivities() == null) {
TeamProfile superTeam = ((TeamProfile) e).getSuperTeam();
if (superTeam != top && superTeam != null) {
return getSuppressed(superTeam, checkParent, top);
}
}
}
}
return null;
}
public boolean isInSuppressedList(
BreakdownElementWrapperItemProvider wrapper) {
if (suppressedExternalElementPaths == null) {
return false;
}
// check if wrapper's path is in suppressedExternalElementPaths set
//
String path = getPath(wrapper);
return suppressedExternalElementPaths.contains(path);
}
/**
* Gets the suppressed breakdown element that made the given wrapper become
* suppressed
*
* @param wrapper
* @return
*/
private BreakdownElement getSuppressed(
BreakdownElementWrapperItemProvider wrapper) {
return getSuppressed(wrapper, true);
}
/**
* Gets the suppressed breakdown element that made the given wrapper become
* suppressed
*
* @param wrapper
* @return
*/
private BreakdownElement getSuppressed(
BreakdownElementWrapperItemProvider wrapper, boolean checkBase) {
return getSuppressed(wrapper, checkBase, true,
autoInheritIntermediateSuppressionState);
}
/**
* Gets the suppressed breakdown element that made the given wrapper become
* suppressed
*
* @param wrapper
* @return
*/
private BreakdownElement getSuppressed(
BreakdownElementWrapperItemProvider wrapper, boolean checkBase,
boolean checkLocal, boolean inheritSuppressionState) {
return getSuppressed(wrapper, checkBase, checkLocal, inheritSuppressionState, true, null);
}
private BreakdownElement getSuppressed(
BreakdownElementWrapperItemProvider wrapper, boolean checkBase,
boolean checkLocal, boolean inheritSuppressionState, boolean checkParent, Object top) {
BreakdownElement e = (BreakdownElement) TngUtil.unwrap(wrapper);
if (!wrapper.isReadOnly()) {
// this is a wrapper of local element
//
return getSuppressed(e, checkParent, top);
}
// check if the base breakdown element is suppressed, directly or
// indirectly, in its own process
//
if (checkBase) {
BreakdownElement suppressed = getSuppressed(e, checkParent, top);
if (suppressed != null) {
return suppressed;
}
}
Object parent = null;
if (checkLocal) {
// check if the wrapper is suppressed in this process
//
if (isInSuppressedList(wrapper)) {
return e;
}
// check if the any local parent is suppressed
//
if(checkParent) {
parent = wrapper.getParent(wrapper);
if (parent instanceof BreakdownElement && parent != top) {
BreakdownElement suppressed = getSuppressed((BreakdownElement) parent, checkParent, top);
if (suppressed != null) {
return suppressed;
}
}
}
}
// check if the breakdown element is suppressed in one of the immediate
// base process
//
if (inheritSuppressionState) {
Process proc = TngUtil.getOwningProcess(e);
Activity inheritor = ProcessUtil.getInheritor(wrapper);
BreakdownElement base = (BreakdownElement) inheritor
.getVariabilityBasedOnElement();
if (base != null) {
Process immediateBaseProc = TngUtil.getOwningProcess(base);
if (proc != immediateBaseProc) {
// find the object in the breakdown structure of the
// immediate
// base process that represents the same breakdown element
//
Object object = inheritor.getVariabilityBasedOnElement();
ArrayList objects = new ArrayList(ProcessUtil
.getParentList(inheritor, wrapper));
objects.add(e);
for (Iterator iter = objects.iterator(); iter.hasNext();) {
Object element = iter.next();
ITreeItemContentProvider adapter = (ITreeItemContentProvider) wrapper
.getAdapterFactory().adapt(object,
ITreeItemContentProvider.class);
find_child: for (Iterator iterator = adapter
.getChildren(object).iterator(); iterator
.hasNext();) {
Object child = iterator.next();
if (element == TngUtil.unwrap(child)) {
object = child;
break find_child;
}
}
}
if (object instanceof BreakdownElementWrapperItemProvider) {
Suppression suppression = getSuppression(immediateBaseProc);
BreakdownElement element = suppression.getSuppressed(
(BreakdownElementWrapperItemProvider) object,
false, true, inheritSuppressionState, checkParent, TngUtil.unwrap(object));
if (element != null) {
return element;
}
}
}
}
}
// check if the any inherited parent is suppressed
//
if(checkParent) {
if (parent == null) {
parent = wrapper.getParent(wrapper);
}
if (parent instanceof BreakdownElementWrapperItemProvider && TngUtil.unwrap(parent) != top) {
return getSuppressed((BreakdownElementWrapperItemProvider) parent,
checkBase, true, inheritSuppressionState, checkParent, top);
}
}
return null;
}
/**
* Gets the cached suppression for the given process if one exists or
* creates new one
*
* @param immediateBaseProc
* @return
*/
public static Suppression getSuppression(Process proc) {
Suppression suppression = (Suppression) procToSuppressionMap.get(proc);
if (suppression == null) {
synchronized (procToSuppressionMap) {
suppression = (Suppression) procToSuppressionMap.get(proc);
if (suppression == null) {
suppression = new Suppression(proc);
procToSuppressionMap.put(proc, suppression);
}
}
}
return suppression;
}
private boolean __isSuppressed(BreakdownElementWrapperItemProvider wrapper) {
return getSuppressed(wrapper) != null;
}
public void saveToModel() {
if (suppressedExternalElementPaths == null) {
return;
}
StringBuffer paths = new StringBuffer();
for (Iterator iter = suppressedExternalElementPaths.iterator(); iter
.hasNext();) {
String path = (String) iter.next();
if (isValid(path)) {
paths.append(path).append(' ');
}
}
Constraint rule = ConstraintManager.getConstraint(process,
ConstraintManager.PROCESS_SUPPRESSION, true);
// if(process.getOwnedRules().isEmpty()) {
// rule = UmaFactory.eINSTANCE.createConstraint();
// process.getOwnedRules().add(rule);
// }
// else {
// rule = (Constraint) process.getOwnedRules().get(0);
// }
//
rule.setBody(paths.toString());
}
/**
* Checks if the given path is valid in process
*
* @param path
* @return
*/
private boolean isValid(String path) {
URI uri = URI.createURI(path);
String type = uri.scheme();
ConfigurableComposedAdapterFactory adapterFactory = null;
if (WBS.equals(type)) {
adapterFactory = (ConfigurableComposedAdapterFactory) TngAdapterFactory.INSTANCE
.getWBS_ComposedAdapterFactory();
} else if (TBS.equals(type)) {
adapterFactory = (ConfigurableComposedAdapterFactory) TngAdapterFactory.INSTANCE
.getOBS_ComposedAdapterFactory();
} else if (WPBS.equals(type)) {
adapterFactory = (ConfigurableComposedAdapterFactory) TngAdapterFactory.INSTANCE
.getPBS_ComposedAdapterFactory();
} else if (CBS.equals(type)) {
adapterFactory = (ConfigurableComposedAdapterFactory) TngAdapterFactory.INSTANCE
.getProcessComposedAdapterFactory();
} else {
return false;
}
// use process's default configuration to validate
//
MethodConfiguration currentConfig = null;
IConfigurator configurator = null;
IFilter filter = adapterFactory.getFilter();
if (filter instanceof IConfigurator) {
configurator = (IConfigurator) adapterFactory.getFilter();
currentConfig = configurator.getMethodConfiguration();
configurator.setMethodConfiguration(process.getDefaultContext());
}
try {
String guid = uri.authority();
if (!process.getGuid().equals(guid)) {
return false;
}
Object object = process;
ITreeItemContentProvider adapter = (ITreeItemContentProvider) adapterFactory
.adapt(object, ITreeItemContentProvider.class);
for (int i = 0; i < uri.segmentCount(); i++) {
guid = uri.segment(i);
Iterator iter = adapter.getChildren(object).iterator();
adapter = null;
find_adapter: while (iter.hasNext()) {
Object child = iter.next();
object = TngUtil.unwrap(child);
if (object instanceof MethodElement) {
if (guid.equals(((MethodElement) object).getGuid())) {
if (child instanceof ITreeItemContentProvider) {
adapter = (ITreeItemContentProvider) child;
} else {
adapter = (ITreeItemContentProvider) adapterFactory
.adapt(child,
ITreeItemContentProvider.class);
}
break find_adapter;
}
} else {
// must be an ItemProviderAdapter
//
ItemProviderAdapter itemProvider = (ItemProviderAdapter) object;
MethodElement e = (MethodElement) itemProvider
.getTarget();
if (guid.equals(e.getGuid())) {
adapter = (ITreeItemContentProvider) itemProvider;
break find_adapter;
}
}
}
if (adapter == null) {
return false;
}
}
return true;
} finally {
// restore configuration
//
if (configurator != null) {
configurator.setMethodConfiguration(currentConfig);
}
}
}
// private boolean reveal(List selection, Collection revealedDescriptors) {
// boolean readOnlyElementAffected = false;
// for (Iterator iter = selection.iterator(); iter.hasNext();) {
// Object element = (Object) iter.next();
// if (element instanceof BreakdownElementWrapperItemProvider) {
// BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) element;
// MethodElement e = (MethodElement) TngUtil.unwrap(wrapper);
// if (!wrapper.isReadOnly()) { // wrapper of local element
// e.setSuppressed(Boolean.FALSE);
// if(e instanceof Descriptor) {
// revealedDescriptors.add(e);
// }
// } else { // was suppressed by this process
//
// // remove the path of suppressed element from the list
// //
// String path = getPath(wrapper);
// getSuppressedExternalElementPaths().remove(path);
// readOnlyElementAffected = true;
// }
// } else if (element instanceof MethodElement) {
// ((MethodElement) element).setSuppressed(Boolean.FALSE);
// if(element instanceof Descriptor) {
// revealedDescriptors.add(element);
// }
// }
// }
// modified = true;
// return readOnlyElementAffected;
// }
// /**
// * @param selection
// * @return true if this call revealed any read-only element
// */
// public boolean reveal(List selection) {
// ArrayList revealedDescriptors = new ArrayList();
// boolean ret = reveal(selection, revealedDescriptors);
// List descriptorsToReveal = getOwnRelatedElements(revealedDescriptors, false);
// if(descriptorsToReveal != null) {
// boolean ret2 = reveal(descriptorsToReveal, revealedDescriptors);
// return ret || ret2;
// }
// return ret;
// }
/**
* @deprecated need to use {@link SuppressionCommand} instead
*/
public void reveal(List selection) {
doSetSuppressed(selection, false);
}
private static String getViewType(
BreakdownElementWrapperItemProvider wrapper) {
// no need to store separate path for CBS, reuse WBS/TBS/WPBS paths
//
Object e = TngUtil.unwrap(wrapper);
if (e instanceof WorkBreakdownElement) {
return WBS;
} else if (e instanceof TeamProfile || e instanceof RoleDescriptor) {
return TBS;
} else if (e instanceof WorkProductDescriptor) {
return WPBS;
} else {
return ""; //$NON-NLS-1$
}
}
/**
* Gets the process GUID in the given GUID path
*
* @param guidPath
* @return
* @see #getPath(BreakdownElementWrapperItemProvider)
*/
public static String getProcessGUID(String guidPath) {
int id = guidPath.indexOf("://"); //$NON-NLS-1$
if(id != -1) {
int beginIndex = id + 3;
if(beginIndex < guidPath.length()) {
int endIndex = guidPath.indexOf('/', beginIndex);
if(endIndex != -1) {
return guidPath.substring(beginIndex, endIndex);
}
}
}
return null;
}
/**
* @param wrapper
* @return
*/
public static String getPath(BreakdownElementWrapperItemProvider wrapper) {
StringBuffer path = new StringBuffer(); //$NON-NLS-1$
List parentList = ProcessUtil.getParentList(null, wrapper);
if (!parentList.isEmpty()) {
for (Iterator iter = parentList.iterator(); iter.hasNext();) {
MethodElement e = (MethodElement) iter.next();
// exclude TaskDescriptor and RoleDescriptor from the parent
// path b/c those descriptors can be
// parent only in CBS view
if (!(e instanceof TaskDescriptor || e instanceof RoleDescriptor)) {
path.append('/').append(e.getGuid());
}
}
}
MethodElement e = (MethodElement) TngUtil.unwrap(wrapper);
path.append('/').append(e.getGuid());
String viewType = getViewType(wrapper);
path.insert(0, ":/").insert(0, viewType); //$NON-NLS-1$
return path.toString();
}
private static List getOwnRelatedElements(Collection changedDescriptors, boolean suppressed) {
if(!changedDescriptors.isEmpty()) {
ArrayList descriptorsToChange = new ArrayList();
for (Iterator iter = new ArrayList(changedDescriptors).iterator(); iter
.hasNext();) {
Descriptor desc = (Descriptor) iter.next();
Object[] relationships = null;
if(desc instanceof TaskDescriptor) {
relationships = RemoveUnusedDescriptorsCommand.TASK_DESCRIPTOR__RELATIONSHIPS;
}
else if(desc instanceof RoleDescriptor) {
relationships = RemoveUnusedDescriptorsCommand.ROLE_DESCRIPTOR__RELATIONSHIPS;
}
else if(desc instanceof WorkProductDescriptor) {
relationships = RemoveUnusedDescriptorsCommand.WORK_PRODUCT_DESCRIPTOR__RELATIONSHIPS;
}
if(relationships != null) {
for (int i = 0; i < relationships.length; i++) {
Object feature = relationships[i];
boolean isMany;
Object value;
if(feature instanceof OppositeFeature) {
OppositeFeature f = (OppositeFeature) feature;
isMany = f.isMany();
value = ((MultiResourceEObject)desc).getOppositeFeatureValue(f);
}
else {
EStructuralFeature f = (EStructuralFeature) feature;
isMany = f.isMany();
value = desc.eGet(f);
}
if(isMany) {
for (Iterator iterator = ((Collection)value)
.iterator(); iterator.hasNext();) {
Descriptor ref = (Descriptor) iterator.next();
if(ref.getSuppressed().booleanValue() != suppressed &&
!ProcessUtil.checkDescriptorReferences(changedDescriptors, ref)) {
descriptorsToChange.add(ref);
changedDescriptors.add(ref);
}
}
}
else {
Descriptor ref = (Descriptor) value;
if(ref.getSuppressed().booleanValue() != suppressed &&
!ProcessUtil.checkDescriptorReferences(changedDescriptors, ref)) {
descriptorsToChange.add(ref);
changedDescriptors.add(ref);
}
}
}
}
}
return descriptorsToChange;
}
return null;
}
/**
* Suppresses or reveals the given selection
*
* @param selection
* @param suppressed
* @return {@link Result} object that contains the result of this call
*/
private Result setSuppressed(List selection, boolean suppressed) {
Result result = doSetSuppressed(selection, suppressed);
// if descriptors had been suppressed, related elements that are not used anywhere else also need to be suppressed (just like delete)
//
if(!result.descriptors.isEmpty()) {
List descriptorsToSuppress = getOwnRelatedElements(result.descriptors, suppressed);
if(descriptorsToSuppress != null) {
Result result2 = doSetSuppressed(descriptorsToSuppress, suppressed);
// merge results
//
result.elements.addAll(result2.elements);
result.descriptors.addAll(result2.descriptors);
result.paths.addAll(result2.paths);
}
}
return result;
}
/**
* @deprecated need to use {@link SuppressionCommand} instead
*/
public void suppress(List selection) {
doSetSuppressed(selection, true);
}
// public boolean suppress(List selection) {
// ArrayList suppressedDescriptors = new ArrayList();
// boolean ret = suppress(selection, suppressedDescriptors);
//
// // if descriptors had been suppressed, related elements that are not used anywhere else also need to be suppressed (just like delete)
// //
// List descriptorsToSuppress = getOwnRelatedElements(suppressedDescriptors, true);
// if(descriptorsToSuppress != null) {
// ArrayList out = new ArrayList();
// boolean ret2 = suppress(descriptorsToSuppress, out);
// if(out.size() != descriptorsToSuppress.size()) {
// LibraryEditPlugin.getDefault().getLogger().logError("Suppression.suppress(List) is buggy."); //$NON-NLS-1$
// }
// return ret || ret2;
// }
// return ret;
// }
private static class Result {
/** Elements that have been suppressed or revealed */
Collection elements;
/** Descriptors that have been suppressed or revealed */
Collection descriptors;
/** Paths that have been added to or removed from <code>suppressedExternalElementPaths</code> */
Collection paths;
Result() {
elements = new ArrayList();
descriptors = new ArrayList();
paths = new ArrayList();
}
boolean isEmpty() {
return elements.isEmpty() && paths.isEmpty();
}
void clear() {
elements.clear();
descriptors.clear();
paths.clear();
}
}
/**
* Suppresses or reveals the given selection depending on the value of <code>suppressed</code>
*
* @param selection
* @param suppressed
* @return
*/
private Result doSetSuppressed(List selection, boolean suppressed) {
Result result = new Result();
for (Iterator iter = selection.iterator(); iter.hasNext();) {
Object element = (Object) iter.next();
if (element instanceof BreakdownElementWrapperItemProvider) {
BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) element;
// if (!isSuppressed(wrapper)) {
BreakdownElement e = (BreakdownElement) TngUtil
.unwrap(wrapper);
if (!wrapper.isReadOnly()) {
// wrapper of local element
//
if(e.getSuppressed().booleanValue() != suppressed) {
e.setSuppressed(Boolean.valueOf(suppressed));
result.elements.add(e);
if(e instanceof Descriptor) {
result.descriptors.add(e);
}
}
} else {
// add the paths of suppressed element to the map
//
String path = getPath(wrapper);
boolean b;
if(suppressed) {
b = getSuppressedExternalElementPaths().add(path);
}
else {
b = getSuppressedExternalElementPaths().remove(path);
}
if(b) {
result.paths.add(path);
}
// }
}
} else if (element instanceof MethodElement) {
MethodElement e = ((MethodElement) element);
if(e.getSuppressed().booleanValue() != suppressed) {
e.setSuppressed(Boolean.valueOf(suppressed));
result.elements.add(e);
if(e instanceof Descriptor) {
result.descriptors.add(e);
}
}
}
}
modified = !result.isEmpty();
return result;
}
// private boolean suppress(List selection, Collection suppressedDescriptors) {
// boolean readOnlyElementSuppressed = false;
// for (Iterator iter = selection.iterator(); iter.hasNext();) {
// Object element = (Object) iter.next();
// if (element instanceof BreakdownElementWrapperItemProvider) {
// BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) element;
// if (!isSuppressed(wrapper)) {
// BreakdownElement e = (BreakdownElement) TngUtil
// .unwrap(wrapper);
// if (!wrapper.isReadOnly()) {
// // wrapper of local element
// //
// e.setSuppressed(Boolean.TRUE);
// if(e instanceof Descriptor) {
// suppressedDescriptors.add(e);
// }
// } else {
// // add the paths of suppressed element to the map
// //
// String path = getPath(wrapper);
// getSuppressedExternalElementPaths().add(path);
// readOnlyElementSuppressed = true;
// }
// }
// } else if (element instanceof MethodElement) {
// ((MethodElement) element).setSuppressed(Boolean.TRUE);
// if(element instanceof Descriptor) {
// suppressedDescriptors.add(element);
// }
// }
// }
// modified = true;
// return readOnlyElementSuppressed;
// }
/**
* @param selection
* @return
*/
public boolean hasUnsuppressed(List selection) {
for (Iterator iter = selection.iterator(); iter.hasNext();) {
Object element = iter.next();
if (element instanceof BreakdownElementWrapperItemProvider) {
if (!isSuppressed((BreakdownElementWrapperItemProvider) element)) {
return true;
}
} else if (element instanceof BreakdownElement) {
if (!isSuppressed((BreakdownElement) element)) {
return true;
}
}
}
return false;
}
/**
* @return Returns the modified.
*/
public boolean isSaveNeeded() {
return modified;
}
public void saveIsDone() {
modified = false;
}
/**
* check if the element, or the item provider or adaptor associated with the
* element is suppressed.
*
* @param e
* MethodElement or an associated wrapper, adaptor, or item
* provider, etc.
* @return boolean
*/
public boolean isSuppressed(Object e) {
// long start = System.currentTimeMillis();
try {
if (e == null) {
return true;
}
if (internalUnsuppressedElements.contains(e)) {
return false;
}
if (e instanceof BreakdownElementWrapperItemProvider) {
return __isSuppressed((BreakdownElementWrapperItemProvider) e);
} else if (e instanceof BreakdownElement) {
return __isSuppressed((BreakdownElement) e);
} else {
Object targetObj = null;
if (e instanceof WrapperItemProvider) {
targetObj = ((WrapperItemProvider) e).getValue();
} else if (e instanceof ItemProviderAdapter) {
targetObj = ((ItemProviderAdapter) e).getTarget();
}
if (targetObj != null && targetObj != e) {
return isSuppressed(targetObj);
}
}
return false;
}
finally {
// long time = (System.currentTimeMillis() - start);
// if(time > 1000) {
// BreakdownElement be = (BreakdownElement)TngUtil.unwrap(e);
// String msg = "Suppression.isSuppressed(): time taken (ms) " + time +
// "\n process: " + (e instanceof BreakdownElementWrapperItemProvider ? ((BreakdownElementWrapperItemProvider)e).getTopItem() : TngUtil.getOwningProcess(be)) +
// "\n element: " + ProcessUtil.getLabelWithPath(be);
//
// System.out.println(msg);
// LibraryEditPlugin.getDefault().getLogger().logInfo(msg);
// }
}
}
/**
* Updates the suppression state of the given <code>wrapper</code> from
* its base.
*
* @param wrapper
* @return <code>true</code> if this call modified the suppression state
* of the given wrapper, <code>false</code> otherwise
*/
public boolean updateSuppressionFromBase(
BreakdownElementWrapperItemProvider wrapper) {
String path = getPath(wrapper);
boolean ret;
BreakdownElement e = getSuppressed(wrapper, true, false, true, false, null);
if (e != null) {
ret = getSuppressedExternalElementPaths().add(path);
} else {
ret = getSuppressedExternalElementPaths().remove(path);
}
if (ret) {
modified = true;
}
return ret;
}
/**
* Excludes the descriptors with the same linked element from the check
*
* @param selectionToReveal
* @return
*/
public String checkDuplicateNameAfterReveal(
Collection selectionToRevealOrSuppress,
AdapterFactory adapterFactory) {
Collection elementsToReveal = getApplicableItems(
selectionToRevealOrSuppress, false);
for (Iterator iter = elementsToReveal.iterator(); iter.hasNext();) {
Object element = iter.next();
if (element instanceof BreakdownElement) {
BreakdownElement be = (BreakdownElement) element;
String msg = ProcessUtil.checkBreakdownElementName(
adapterFactory, be, be.getName(), this);
if (msg != null) {
return LibraryEditResources.Suppression_nameDuplication; //$NON-NLS-1$
}
msg = ProcessUtil.checkBreakdownElementPresentationName(
adapterFactory, be, be.getPresentationName(), this);
if (msg != null) {
return LibraryEditResources.Suppression_presentationNameDuplication; //$NON-NLS-1$
}
} else {
Object unwrapped = TngUtil.unwrap(element);
if (unwrapped instanceof BreakdownElement) {
ITreeItemContentProvider itemProvider = (ITreeItemContentProvider) adapterFactory
.adapt(element, ITreeItemContentProvider.class);
Object parent = itemProvider.getParent(element);
if (parent instanceof BreakdownElement) {
itemProvider = (ITreeItemContentProvider) adapterFactory
.adapt(parent, ITreeItemContentProvider.class);
Collection siblings = itemProvider.getChildren(parent);
Object linkedElement = null;
if (element instanceof Descriptor) {
linkedElement = ProcessUtil
.getAssociatedElement((Descriptor) element);
}
try {
internalUnsuppressedElements.add(element);
nameCheckLoop: for (Iterator iterator = siblings
.iterator(); iterator.hasNext();) {
Object sibling = iterator.next();
if (sibling instanceof BreakdownElement) {
BreakdownElement be = (BreakdownElement) sibling;
// skip checking on suppressed element
//
if (be.getSuppressed().booleanValue()) {
continue nameCheckLoop;
}
if (linkedElement != null
&& sibling instanceof Descriptor) {
// skip checking on descriptors with the
// same linked element
//
Object otherLinkedElement = ProcessUtil
.getAssociatedElement((Descriptor) element);
if (otherLinkedElement == linkedElement) {
continue nameCheckLoop;
}
}
String msg = ProcessUtil
.checkBreakdownElementName(
adapterFactory, be, be
.getName(), this);
if (msg != null) {
return LibraryEditResources.Suppression_nameDuplication; //$NON-NLS-1$
}
msg = ProcessUtil
.checkBreakdownElementPresentationName(
adapterFactory, be,
be.getPresentationName(),
this);
if (msg != null) {
return LibraryEditResources.Suppression_presentationNameDuplication; //$NON-NLS-1$
}
}
}
} finally {
internalUnsuppressedElements.remove(element);
}
}
}
}
}
return null;
}
public Object getObjectByPath(String[] guidPath,
AdapterFactory adapterFactory) {
if (guidPath.length == 0 || adapterFactory == null
|| !guidPath[0].equals(process.getGuid())) {
return null;
}
Object object = process;
int len = guidPath.length;
for (int i = 1; i < len; i++) {
ITreeItemContentProvider adapter = (ITreeItemContentProvider) adapterFactory
.adapt(object, ITreeItemContentProvider.class);
boolean found = false;
// if current object is an activity, make sure it is rolled down before looking into its children
//
IBSItemProvider rolledUpAdapter = null;
Iterator iter = null;
try {
if(TngUtil.unwrap(object) instanceof Activity) {
if(adapter instanceof BSActivityItemProvider) {
BSActivityItemProvider activityItemProvider = (BSActivityItemProvider) adapter;
if(activityItemProvider.isRolledUp()) {
activityItemProvider.basicSetRolledUp(false);
rolledUpAdapter = activityItemProvider;
}
}
else if(adapter instanceof IBSItemProvider) {
IBSItemProvider itemProvider = (IBSItemProvider) adapter;
if(itemProvider.isRolledUp()) {
itemProvider.setRolledUp(false);
rolledUpAdapter = itemProvider;
}
}
}
iter = adapter.getChildren(object).iterator();
}
finally {
if(rolledUpAdapter != null) {
rolledUpAdapter.setRolledUp(true);
}
}
find_child: while (iter.hasNext()) {
Object child = iter.next();
Object e = TngUtil.unwrap(child);
if (e instanceof MethodElement
&& ((MethodElement) e).getGuid().equals(guidPath[i])) {
found = true;
object = child;
break find_child;
}
}
if (!found) {
return null;
}
}
return object;
}
/**
* Checks if the breakdown element identified by the given
* <code>guidPath</code> is suppressed in the process of this Suppression
* object
*
* @param guidPath
* @return
* @exception IllegalArgumentException
* if the object with the given path could not be found using
* the given adapter factory
*/
public boolean isSuppressed(String[] guidPath, AdapterFactory adapterFactory)
throws IllegalArgumentException {
Object object = getObjectByPath(guidPath, adapterFactory);
if (object == null) {
throw new IllegalArgumentException(
"Could not find object with path '" + guidPath + "'"); //$NON-NLS-1$ //$NON-NLS-2$
}
return isSuppressed(object);
}
/**
* Gets the set of suppressed item of the given processes.
*
* @param proc
* @param adapterFactories the adapter factories for WBS, TBS, WPBS, and CBS views
* @return
*/
public static Set getSuppressedItems(Process proc, AdapterFactory[] adapterFactories) {
Set suppressedItems = new HashSet();
Suppression suppression = new Suppression(proc);
for (int i = 0; i < adapterFactories.length; i++) {
for (Iterator iter = new AdapterFactoryTreeIterator(adapterFactories[i], proc); iter.hasNext();) {
Object item = iter.next();
if(suppression.isSuppressed(item)) {
suppressedItems.add(item);
}
}
}
return suppressedItems;
}
public static class SuppressionCommand extends AbstractCommand implements IResourceAwareCommand
{
private Collection modifiedResources;
private List collection;
private Result result;
private boolean suppressed;
private Suppression suppression;
public SuppressionCommand(Suppression suppression, List selection, boolean suppressed) {
this.suppression = suppression;
collection = selection;
this.suppressed = suppressed;
}
/* (non-Javadoc)
* @see org.eclipse.epf.library.edit.command.IResourceAwareCommand#getModifiedResources()
*/
public Collection getModifiedResources() {
if(modifiedResources == null) {
modifiedResources = Collections.singletonList(suppression.getProcess().eResource());
}
return modifiedResources;
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.Command#execute()
*/
public void execute() {
result = suppression.setSuppressed(collection, suppressed);
didExecute();
}
/**
*
*/
protected void didExecute() {
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.Command#redo()
*/
public void redo() {
execute();
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.AbstractCommand#undo()
*/
public void undo() {
if(result != null && !result.isEmpty()) {
if(!result.elements.isEmpty()) {
for (Iterator iter = result.elements.iterator(); iter.hasNext();) {
MethodElement e = (MethodElement) iter.next();
e.setSuppressed(Boolean.valueOf(!suppressed));
}
}
if(!result.paths.isEmpty()) {
for (Iterator iter = result.paths.iterator(); iter.hasNext();) {
Object path = iter.next();
if(suppressed) {
suppression.getSuppressedExternalElementPaths().remove(path);
}
else {
suppression.getSuppressedExternalElementPaths().add(path);
}
}
}
didUndo();
result.clear();
}
}
/**
*
*/
protected void didUndo() {
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.AbstractCommand#prepare()
*/
protected boolean prepare() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.AbstractCommand#getResult()
*/
public Collection getResult() {
if(!result.isEmpty()) {
return collection;
}
return Collections.EMPTY_LIST;
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.AbstractCommand#getAffectedObjects()
*/
public Collection getAffectedObjects() {
return collection;
}
public boolean isReadOnlyElementAffected() {
return !result.paths.isEmpty();
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.AbstractCommand#dispose()
*/
public void dispose() {
if(result != null) {
result.clear();
}
super.dispose();
}
}
}