blob: 0d2f282598cc694aee88d4c084d624643a440bd7 [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
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// 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.bridge;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.epf.diagram.model.util.IAdapterFactoryFilter;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.command.IActionManager;
import org.eclipse.epf.library.edit.process.ActivityWrapperItemProvider;
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.WBSActivityItemProvider;
import org.eclipse.epf.library.edit.util.ConfigurableComposedAdapterFactory;
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.MethodElement;
import org.eclipse.epf.uma.Milestone;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.UmaFactory;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.WorkBreakdownElement;
import org.eclipse.epf.uma.WorkOrder;
import org.eclipse.uml2.uml.ActivityEdge;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.ActivityParameterNode;
import org.eclipse.uml2.uml.ControlNode;
import org.eclipse.uml2.uml.StructuredActivityNode;
import org.eclipse.uml2.uml.UMLFactory;
/**
* @author Phong Nguyen Le
* @author Shilpa Toraskar
*
* @since 1.2
*/
public class ActivityDiagramAdapter extends DiagramAdapter {
public ActivityDiagramAdapter(BreakdownElementWrapperItemProvider wrapper) {
super(wrapper);
}
/**
* @param e
*/
public ActivityDiagramAdapter(Activity e) {
super(e);
}
protected ActivityNode addNode(Collection nodes, Object obj) {
if (obj instanceof Activity) {
Activity act = (Activity) obj;
VariabilityElement base = act.getVariabilityBasedOnElement();
if (base != null) {
// find existing node for base and link it to the activity
//
org.eclipse.uml2.uml.Activity diagram = getDiagram();
ActivityNode baseNode = BridgeHelper.findNode(diagram, base);
if (baseNode == null) {
baseNode = BridgeHelper.findNode(diagram, act);
}
if (baseNode != null) {
// disassociate with the base
//
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(baseNode);
if(nodeAdapter != null) {
nodeAdapter.dispose();
}
// associate base node with the activity
//
nodeAdapter = createNodeAdapter(act);
if(nodeAdapter != null) {
initializeNodeAdapter(nodeAdapter);
baseNode.eAdapters().add(nodeAdapter);
nodeAdapter.updateView();
// if(ProcessUtil.isExtendingOrLocallyContributing(act)) {
BridgeHelper.associate(baseNode, act);
if(BridgeHelper.isInherited(nodeAdapter.getView())){
BridgeHelper.unmarkInHerited(nodeAdapter.getView());
}
nodeAdapter.setTargetReadOnly(false);
// }
}
return null;
}
}
}
return super.addNode(nodes, obj);
}
protected NodeAdapter createNodeAdapter(MethodElement e) {
if(e instanceof WorkBreakdownElement) {
return new WorkBreakdownElementNodeAdapter(e);
}
return null;
}
protected void addToUmaModel(int position, ActivityNode addedNode) {
MethodElement e = BridgeHelper.getMethodElement(addedNode);
if(e == null) {
return;
}
Activity act = (Activity) getElement();
// translate ActivityNode index to Activity index
//
int i = toActivityIndex(position);
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(addedNode);
boolean notify = nodeAdapter.notificationEnabled;
try {
nodeAdapter.notificationEnabled = false;
getActionManager().doAction(IActionManager.ADD, act, UmaPackage.Literals.ACTIVITY__BREAKDOWN_ELEMENTS, e, i);
BridgeHelper.addEAnnotation(addedNode, e);
}
finally {
nodeAdapter.notificationEnabled = notify;
}
super.addToUmaModel(position, addedNode);
}
private int toActivityIndex(int index) {
if (index == -1)
return index;
int size = getNodes().size();
int i = index + 1;
if (i == size)
return -1;
ActivityNode node = (ActivityNode) getNodes().get(i);
if (node == null)
return -1;
for (; !(BridgeHelper.getMethodElement(node) instanceof BreakdownElement) && i < size; i++) {
node = (ActivityNode) getNodes().get(i);
}
if (i == size)
return -1;
Activity act = (Activity) getElement();
return act.getBreakdownElements().indexOf(BridgeHelper.getMethodElement(node));
}
protected List getBreakdownElementTypes() {
return Collections.singletonList(WorkBreakdownElement.class);
}
/* (non-Javadoc)
* @see org.eclipse.epf.diagram.core.bridge.DiagramAdapter#newNode(org.eclipse.epf.uma.MethodElement)
*/
protected ActivityNode newNode(MethodElement e) {
ActivityNode node = null;
if(e instanceof Activity ) {
node = UMLFactory.eINSTANCE.createStructuredActivityNode();
}
else if(e instanceof TaskDescriptor || e instanceof Milestone) {
node = UMLFactory.eINSTANCE.createActivityParameterNode();
}
else if(e instanceof WorkBreakdownElement) {
node = UMLFactory.eINSTANCE.createStructuredActivityNode();
}
if(node != null) {
BridgeHelper.associate(node, e);
}
return node;
}
private boolean isValid(ActivityEdge link) {
if (link.getSource() == null || link.getTarget() == null
|| !getNodes().contains(link.getSource())
|| !getNodes().contains(link.getTarget())) {
return false;
}
return true;
}
private static boolean isValidWorkOrder(WorkOrder wo, Object pred) {
if (wo.getPred() == pred) {
return true;
}
if (pred instanceof Activity) {
Activity act = (Activity) pred;
// check if predecessor reference in the given work order is base of
// pred
//
for (VariabilityElement ve = act.getVariabilityBasedOnElement(); ve != null; ve = ve
.getVariabilityBasedOnElement()) {
if (ve == wo.getPred()) {
return true;
}
}
}
return false;
}
/**
* Checks if Node src can reach Node target as the first ActivityNode in the
* diagram
*
* @param predNode
* @param node
* @return
*/
private static boolean canReachAsFirstActivityNode(ActivityNode predNode, ActivityNode node) {
for (Iterator iter = predNode.getOutgoings().iterator(); iter
.hasNext();) {
ActivityEdge link = (ActivityEdge) iter.next();
if (link.getTarget() == node) {
return true;
}
if (link.getTarget() instanceof ControlNode
&& canReachAsFirstActivityNode(link.getTarget(), node)) {
return true;
}
}
return false;
}
AdapterFactory getAdapterFactory(){
AdapterFactory adapterFactory = null;
if (filter == null) {
adapterFactory = TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory();
} else if (filter instanceof IAdapterFactoryFilter) {
adapterFactory = (ConfigurableComposedAdapterFactory) ((IAdapterFactoryFilter) filter)
.getWBSAdapterFactory();
}
return adapterFactory;
}
@Override
protected void populateLinks(List<ActivityNode> selectedNodes) {
if(selectedNodes.isEmpty()) {
return;
}
super.populateLinks(selectedNodes);
// remove the invalid links
//
for (ActivityNode node : selectedNodes) {
WorkBreakdownElement wbe = null;
MethodElement me;
if ((me = BridgeHelper.getMethodElement(node)) instanceof WorkBreakdownElement) {
wbe = (WorkBreakdownElement) me;
}
ArrayList<ActivityEdge> linksToRemove = new ArrayList<ActivityEdge>();
linkListWalk: for (Iterator iterator = node
.getIncomings().iterator(); iterator.hasNext();) {
ActivityEdge link = (ActivityEdge) iterator.next();
if (!isValid(link)) {
linksToRemove.add(link);
}
if (wbe != null) {
// TODO: need revisit to check the valid connection from a
// ForkNode or JoinNode
//
if (link.getSource() != null && link.getSource() instanceof ControlNode)
continue linkListWalk;
Object pred = BridgeHelper.getMethodElement(link.getSource());
boolean workOrderFound = false;
find_WorkOrder: for (Iterator iterator1 = wbe
.getLinkToPredecessor().iterator(); iterator1
.hasNext();) {
WorkOrder wo = (WorkOrder) iterator1.next();
if (isValidWorkOrder(wo, pred)) {
workOrderFound = true;
break find_WorkOrder;
}
}
if (!workOrderFound) {
// invalid link, remove it
//
linksToRemove.add(link);
}
}
}
for (ActivityEdge link : linksToRemove) {
BridgeHelper.removeLink(link);
}
linksToRemove.clear();
for (Iterator iterator = node.getOutgoings().iterator(); iterator
.hasNext();) {
ActivityEdge link = (ActivityEdge) iterator.next();
if (!isValid(link)) {
linksToRemove.add(link);
}
}
for (Iterator iterator = linksToRemove.iterator(); iterator
.hasNext();) {
ActivityEdge link = (ActivityEdge) iterator.next();
BridgeHelper.removeLink(link);
}
linksToRemove.clear();
linksToRemove = null;
}
// Check the links of each ActivityNode
// set the WorkOrder to the link if needed
// add new link for those WorkOrders that still don't have the
// corresponding link
//
AdapterFactory adapterFactory = getAdapterFactory();
for (ActivityNode node : selectedNodes) {
MethodElement e;
if ((e = BridgeHelper.getMethodElement(node)) instanceof WorkBreakdownElement) {
List list = new ArrayList();
// Get the raw data of workorders for object.
WorkBreakdownElement local = (WorkBreakdownElement) e;
list.addAll(local.getLinkToPredecessor());
// Get the Predecessor List on top of raw data, this is need for in case of extend.
ITreeItemContentProvider adapter = null;
adapter = (ITreeItemContentProvider)adapterFactory
.adapt(local, ITreeItemContentProvider.class);
if(adapter instanceof IBSItemProvider){
list.addAll(((IBSItemProvider)adapter).getPredecessors());
}
// Iterate work orders and create links.
for (Iterator iterator = list.iterator(); iterator
.hasNext();) {
Object next = iterator.next();
WorkOrder workOrder = null;
BreakdownElement pred = null;
if(next instanceof WorkOrder){
workOrder = (WorkOrder)next;
pred = workOrder.getPred();
}
if(next instanceof WBSActivityItemProvider){
pred = (BreakdownElement)((WBSActivityItemProvider)next).getTarget();
}
if (pred != null && pred instanceof WorkBreakdownElement) {
ActivityNode predNode = BridgeHelper.findNode(getDiagram(),
pred, true);
if (predNode != null) {
// check if there is a link for this work order
// already
//
boolean linkFound = false;
find_link: for (Iterator iterator1 = node
.getIncomings().iterator(); iterator1
.hasNext();) {
ActivityEdge link = (ActivityEdge) iterator1.next();
if (link.getSource() == predNode) {
// link already exists
// check if work order is set to this link
//
linkFound = true;
// MethodElement me = BridgeHelper.getMethodElement(link);
if (link == null) {
BridgeHelper.setSemanticModel(
link, workOrder);
}
break find_link;
}
}
if (!linkFound) {
// check if this WorkOrder can be represented
// via links of TypedNodes
//
if (!canReachAsFirstActivityNode(predNode, node)) {
// add new link for this work order
//
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
NodeAdapter predNodeAdapter = BridgeHelper.getNodeAdapter(predNode);
if(nodeAdapter != null && predNodeAdapter != null) {
boolean oldNotify = nodeAdapter.notificationEnabled;
boolean predNodeNotify = predNodeAdapter.notificationEnabled;
try {
nodeAdapter.notificationEnabled = false;
predNodeAdapter.notificationEnabled = false;
nodeAdapter.addIncomingConnection(pred);
} finally {
nodeAdapter.notificationEnabled = oldNotify;
predNodeAdapter.notificationEnabled = predNodeNotify;
}
}
}
}
}
}
}
}
}
cleanDuplicateLinks(selectedNodes);
}
private void cleanDuplicateLinks(List<ActivityNode> selectedNodes) {
List<ActivityEdge> duplicateLinks = new ArrayList<ActivityEdge>();
for (ActivityNode wbNode : selectedNodes) {
if(wbNode.getIncomings() != null){
findDuplicateLinks(duplicateLinks, wbNode.getIncomings());
}
if(wbNode.getOutgoings() !=null){
findDuplicateLinks(duplicateLinks, wbNode.getOutgoings());
}
}
for (ActivityEdge link : duplicateLinks) {
BridgeHelper.removeLink(link);
}
duplicateLinks.clear();
duplicateLinks = null;
}
private void findDuplicateLinks(List duplicateLinks, List links) {
for (int i = 0; i < links.size(); i++) {
ActivityEdge link = (ActivityEdge) links.get(i);
if(!duplicateLinks.contains(link)){
for (int j = i + 1; j < links.size(); j++) {
ActivityEdge link1 = (ActivityEdge) links.get(j);
if (link1.getSource() == link.getSource()
&& link1.getTarget() == link.getTarget()) {
duplicateLinks.add(link1);
}
}
}
}
}
protected Collection populateNodes() {
HashSet selectedNodes = new HashSet();
Collection children = getChildren();
// associate control nodes
//
selectedNodes.addAll(associateControlNodes(children));
// add WorkBreakdownElementNodes
//
selectedNodes.addAll(addElementNodes(children));
return selectedNodes;
}
private List associateControlNodes(Collection methodElements) {
List ctrlNodes = new ArrayList();
for (Iterator iter = getDiagram().getNodes().iterator(); iter.hasNext();) {
ActivityNode node = (ActivityNode) iter.next();
if(node instanceof ControlNode) {
// // select this control node for the diagram only if it has a target node or source node,
// // direct or indirect, that is associated with a method element in the specified
// // method element collection
// //
// Collection actNodes = new ArrayList();
// BridgeHelper.getTargetNodes(actNodes, node, WorkBreakdownElement.class);
// BridgeHelper.getSourceNodes(actNodes, node, WorkBreakdownElement.class);
// if(!actNodes.isEmpty()) {
// for (Iterator iterator = actNodes.iterator(); iterator
// .hasNext();) {
// ActivityNode elementNode = (ActivityNode) iterator.next();
// if(methodElements.contains(BridgeHelper.getMethodElement(elementNode))) {
// if(addNodeAdapterTo(node) != null) {
// ctrlNodes.add(node);
// }
// }
// }
// }
if(addNodeAdapterTo(node) != null) {
ctrlNodes.add(node);
}
}
}
return ctrlNodes;
}
/**
* Adds element nodes for the specified method elements if they don't exist yet.
*
* @param methodElements
*/
private List addElementNodes(Collection methodElements) {
ArrayList nodes = new ArrayList();
ArrayList newNodes = new ArrayList();
for (Iterator iter = methodElements.iterator(); iter.hasNext();) {
Object e = iter.next();
Object child = TngUtil.unwrap(e);
if (child instanceof WorkBreakdownElement) {
ActivityNode node = BridgeHelper.findNode(getDiagram(), child);
if(node == null) {
node = toNode((MethodElement) child);
newNodes.add(node);
}
else {
// synchronize name with linked element
//
String name = BridgeHelper.getNodeName((MethodElement) child);
if(!name.equals(node.getName())) {
node.setName(name);
}
addNodeAdapterTo(node);
}
nodes.add(node);
if (e instanceof BreakdownElementWrapperItemProvider && !isTargetReadOnly()) {
BreakdownElementWrapperItemProvider wrapper = ((BreakdownElementWrapperItemProvider) e);
if (wrapper.isReadOnly()) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
nodeAdapter.wrapper = wrapper;
// readOnly attribute is still needed
// after introduction of wrapper.
// For example, we can have a node adapter for a read-only base activity
// without supplying wrapper for this base activity.
//
nodeAdapter.basicSetTargetReadOnly(true);
}
}
}
}
getNodes().addAll(newNodes);
return nodes;
}
/**
* Moved code from getChildren. getAdapter() will return Adapter,
* which will allow us to find itemprovider for the children.
*
* @return
*/
private ITreeItemContentProvider getAdapter(){
ITreeItemContentProvider adapter = null;
if (wrapper != null) {
adapter = wrapper;
} else {
adapter = (ITreeItemContentProvider) getAdapterFactory().adapt(
getElement(), ITreeItemContentProvider.class);
}
return adapter;
}
public Collection getChildren() {
ITreeItemContentProvider adapter = getAdapter();
if (adapter != null) {
//Turn off the VariabilityInfo for the activity diagram.
Object obj = null;
boolean enableVariabilityInfo = false;
if(adapter instanceof ActivityWrapperItemProvider){
obj = ((ActivityWrapperItemProvider)adapter).getDelegatingItemProvider();
}
if(adapter instanceof BSActivityItemProvider){
obj = adapter;
}
if(obj instanceof BSActivityItemProvider){
enableVariabilityInfo = ((BSActivityItemProvider)obj).isEnableVariabilityInfo();
((BSActivityItemProvider)obj).setEnableVariabilityInfo(false);
}
// end of variability info
// return adapter.getChildren(getObject());
// commented above line, For diagrams - rollup should be false, for
// handling rollup state below code.
List children = new ArrayList();
extractChildren(adapter, getElement(), children);
// reset variabilityinfo status back
if(obj instanceof BSActivityItemProvider){
((BSActivityItemProvider)obj).setEnableVariabilityInfo(enableVariabilityInfo);
}
return children;
} else {
return Collections.EMPTY_LIST;
}
}
protected boolean removeNode(Object obj) {
if (obj instanceof Activity) {
Activity act = (Activity) obj;
VariabilityElement base = act.getVariabilityBasedOnElement();
if (base != null) {
org.eclipse.uml2.uml.Activity diagram = getDiagram();
// find existing node for the old activity and relink it to its
// base
//
ActivityNode node = BridgeHelper.findNode(diagram, act);
if(node == null) {
node = BridgeHelper.findNode(diagram, base);
}
if (node != null) {
// disassociate with the old activity
//
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
if(nodeAdapter != null) {
nodeAdapter.dispose();
}
// associate node with the base activity
//
nodeAdapter = createNodeAdapter(base);
if(nodeAdapter != null) {
initializeNodeAdapter(nodeAdapter);
nodeAdapter.basicSetTargetReadOnly(true);
node.eAdapters().add(nodeAdapter);
nodeAdapter.updateView();
if(!BridgeHelper.isInherited(nodeAdapter.getView())){
BridgeHelper.markInherited(nodeAdapter.getView());
}
}
return false;
}
}
}
return super.removeNode(obj);
}
protected NodeAdapter addNodeAdapterTo(ActivityNode node) {
NodeAdapter adapter = BridgeHelper.getNodeAdapter(node);
if(adapter != null) {
return adapter;
}
if(node instanceof ControlNode) {
adapter = new ControlNodeAdapter();
}
else {
MethodElement e = BridgeHelper.getMethodElement(node);
if(e == null) {
if(node instanceof StructuredActivityNode) {
String type = BridgeHelper.getType((StructuredActivityNode)node);
if (BridgeHelper.UMA_PHASE.equals(type)) {
e = UmaFactory.eINSTANCE.createPhase();
}
else if (BridgeHelper.UMA_ITERATION.equals(type)) {
e = UmaFactory.eINSTANCE.createIteration();
}
else {
e = UmaFactory.eINSTANCE.createActivity();
}
}
else if(node instanceof ActivityParameterNode) {
String type = BridgeHelper.getType((ActivityParameterNode)node);
if(BridgeHelper.UMA_MILESTONE.equals(type)) {
e = UmaFactory.eINSTANCE.createMilestone();
}
else {
e = UmaFactory.eINSTANCE.createTaskDescriptor();
}
}
}
if(e != null) {
adapter = new WorkBreakdownElementNodeAdapter(e);
}
}
if(adapter != null) {
initializeNodeAdapter(adapter);
node.eAdapters().add(adapter);
return adapter;
}
return null;
}
private ActivityNode reassociateBaseNode(Activity act) {
VariabilityElement base = act.getVariabilityBasedOnElement();
if (base != null) {
// find existing node for base and link it to the activity
//
org.eclipse.uml2.uml.Activity diagram = getDiagram();
ActivityNode baseNode = BridgeHelper.findNode(diagram, base);
if (baseNode == null) {
baseNode = BridgeHelper.findNode(diagram, act);
}
if (baseNode != null) {
// disassociate with the base
//
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(baseNode);
if(nodeAdapter != null) {
nodeAdapter.dispose();
}
// associate base node with the activity
//
nodeAdapter = createNodeAdapter(act);
if(nodeAdapter != null) {
initializeNodeAdapter(nodeAdapter);
baseNode.eAdapters().add(nodeAdapter);
nodeAdapter.updateView();
// if(ProcessUtil.isExtendingOrLocallyContributing(act)) {
BridgeHelper.associate(baseNode, act);
if(BridgeHelper.isInherited(nodeAdapter.getView())){
BridgeHelper.unmarkInHerited(nodeAdapter.getView());
}
nodeAdapter.setTargetReadOnly(false);
// }
}
return baseNode;
}
}
return null;
}
@Override
protected void replaceNode(Object oldElement, Object newElement) {
if(newElement instanceof MethodElement) {
// find existing node for old element and link it to the new element
//
org.eclipse.uml2.uml.Activity diagram = getDiagram();
ActivityNode oldNode = BridgeHelper.findNode(diagram, oldElement);
if (oldNode != null) {
// disassociate with the old element
//
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(oldNode);
if(nodeAdapter != null) {
nodeAdapter.dispose();
}
// associate base node with the new element
//
MethodElement e = (MethodElement) newElement;
nodeAdapter = createNodeAdapter(e);
if(nodeAdapter != null) {
initializeNodeAdapter(nodeAdapter);
oldNode.eAdapters().add(nodeAdapter);
nodeAdapter.updateView();
BridgeHelper.associate(oldNode, e);
}
}
}
}
}