blob: eef88f8c29e590176510967ffd3cd9a4ca91c5f8 [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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.epf.common.utils.StrUtil;
import org.eclipse.epf.diagram.model.util.TxUtil;
import org.eclipse.epf.library.edit.command.IActionManager;
import org.eclipse.epf.library.edit.process.BreakdownElementWrapperItemProvider;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.DescribableElement;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.WorkBreakdownElement;
import org.eclipse.epf.uma.WorkOrder;
import org.eclipse.epf.uma.util.UmaUtil;
import org.eclipse.gmf.runtime.notation.FontStyle;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.ActivityEdge;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.ControlNode;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
/**
* @author Phong Nguyen Le
*
* @since 1.2
*/
public class NodeAdapter extends AdapterImpl {
protected class MethodElementAdapter extends AdapterImpl //implements INodeChangeListener
{
/**
*
* @param msg
* @return New nodes whose views need refresh after they have been created
*/
protected Collection handleNotification(Notification msg) {
switch (msg.getFeatureID(DescribableElement.class)) {
case UmaPackage.DESCRIBABLE_ELEMENT__PRESENTATION_NAME:
setName(msg.getNewStringValue());
break;
}
return Collections.EMPTY_LIST;
}
public void notifyChanged(final Notification msg) {
if(domain == null || domain.getChangeRecorder() == null) {
return;
}
if (!notificationEnabled)
return;
notificationEnabled = false;
try {
final Collection<ActivityNode> newNodesToRefresh = new ArrayList<ActivityNode>();
TxUtil.runInTransaction(domain, new Runnable() {
public void run() {
newNodesToRefresh.addAll(handleNotification(msg));
}
});
if(!newNodesToRefresh.isEmpty()) {
TxUtil.runInTransaction(domain, new Runnable() {
public void run() {
for (ActivityNode node : newNodesToRefresh) {
BridgeHelper.getNodeAdapter(node).updateView();
}
}
});
}
}
catch(Exception e) {
e.printStackTrace();
} finally {
notificationEnabled = true;
}
}
public NodeAdapter getNodeAdapter() {
return NodeAdapter.this;
}
}
protected MethodElement element;
protected boolean notificationEnabled = true;
private Collection consumers = new ArrayList();
protected MethodElementAdapter methodElementAdapter;
private boolean targetReadOnly;
protected BreakdownElementWrapperItemProvider wrapper;
protected InternalTransactionalEditingDomain domain;
private View view;
protected IActionManager actionManager;
protected NodeAdapter() {
}
public IActionManager getActionManager() {
if(actionManager != null) {
return actionManager;
}
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(getNode().getActivity());
return nodeAdapter.getActionManager();
}
public NodeAdapter(BreakdownElementWrapperItemProvider wrapper) {
this((MethodElement) TngUtil.unwrap(wrapper));
this.wrapper = wrapper;
targetReadOnly = wrapper.isReadOnly();
}
public NodeAdapter(MethodElement e) {
element = e;
methodElementAdapter = createMethodElementAdapter();
e.eAdapters().add(methodElementAdapter);
}
public View getView() {
if(view != null) {
return view;
}
View diagramView = getDiagramView();
if(diagramView != null) {
return BridgeHelper.getView(diagramView, getNode());
}
return null;
}
private View getDiagramView() {
Activity diagram = getDiagram();
if(diagram != null) {
NodeAdapter adapter = BridgeHelper.getNodeAdapter(diagram);
if(adapter != null) {
return adapter.getView();
}
}
return null;
}
public void setView(View view) {
this.view = view;
}
public void setEditingDomain(InternalTransactionalEditingDomain domain) {
this.domain = domain;
}
public boolean isTargetReadOnly() {
if(targetReadOnly) {
return targetReadOnly;
}
Activity activity = getDiagram();
if(activity != target) {
NodeAdapter diagramAdapter = BridgeHelper.getNodeAdapter(activity);
if(diagramAdapter != null && diagramAdapter.isTargetReadOnly()) {
return true;
}
}
return false;
}
protected void basicSetTargetReadOnly(boolean b) {
targetReadOnly = b;
}
protected void setTargetReadOnly(boolean targetReadOnly) {
boolean updateView = this.targetReadOnly != targetReadOnly;
this.targetReadOnly = targetReadOnly;
if(updateView) {
updateView();
}
}
protected void updateView() {
View node = getView();
if(node != null) {
// node.setMutable(!isTargetReadOnly());
FontStyle style = (FontStyle) node.getStyle(NotationPackage.Literals.FONT_STYLE);
// if(style != null) {
// Color color = isTargetReadOnly() ? DiagramConstants.READ_ONLY_FONT_COLOR : DiagramConstants.DEFAULT_FONT_COLOR;
// style.setFontColor(FigureUtilities.RGBToInteger(color.getRGB()).intValue());
// }
if(style == null) {
node.createStyle(NotationPackage.Literals.FONT_STYLE);
}
}
}
protected MethodElementAdapter createMethodElementAdapter() {
return new MethodElementAdapter();
}
protected ActivityNode getNode() {
if(target instanceof ActivityNode) {
return (ActivityNode) target;
}
return null;
}
protected Activity getDiagram() {
if(target instanceof Activity) {
return (Activity) target;
}
ActivityNode node = getNode();
return node != null ? node.getActivity() : null;
}
protected ActivityEdge addIncomingConnection(MethodElement source) {
ActivityNode srcNode = BridgeHelper.findNode(getDiagram(), source, true);
if (srcNode == null)
return null;
// disable notification of srcNode before associate it with the link
// so it will not create duplicate UMA data
//
NodeAdapter srcNodeAdapter = BridgeHelper.getNodeAdapter(srcNode);
boolean notify = srcNodeAdapter != null ? srcNodeAdapter.notificationEnabled : false;
try {
if(srcNodeAdapter != null) srcNodeAdapter.notificationEnabled = false;
ActivityEdge edge = UMLFactory.eINSTANCE.createControlFlow();
edge.setSource(srcNode);
edge.setTarget(getNode());
getDiagram().getEdges().add(edge);
return edge;
} finally {
if(srcNodeAdapter != null) srcNodeAdapter.notificationEnabled = notify;
}
}
protected ActivityEdge addOutgoingConnection(MethodElement target) {
ActivityNode targetNode = BridgeHelper.findNode(getDiagram(), target);
if (targetNode == null)
return null;
// disable notification of targetNode before associate it with the link
// so it will not create duplicate UMA data
//
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(targetNode);
boolean notify = nodeAdapter != null ? nodeAdapter.notificationEnabled : false;
try {
if(nodeAdapter != null) nodeAdapter.notificationEnabled = false;
ActivityEdge edge = getDiagram().createEdge("", UMLPackage.Literals.CONTROL_FLOW); //$NON-NLS-1$
edge.setSource(getNode());
edge.setTarget(targetNode);
return edge;
} finally {
if(nodeAdapter != null) nodeAdapter.notificationEnabled = notify;
}
}
/**
* Adds the given consumer to the consumer list of this node.
*
* @param consumer
*/
public void addConsumer(Object consumer) {
if (!consumers.contains(consumer)) {
consumers.add(consumer);
}
}
/**
* Removes the given consumer from the consumer list of this node. Disposes
* the node if it does not have any more consumer after this call. Disposing
* a node will take care of removing this node's listener from the UMA
* object and all the adapters that had been added to the adapter list of
* this node.
*
* @param consumer
*/
public void removeConsumer(Object consumer) {
consumers.remove(consumer);
if (consumers.isEmpty()) {
// no more consumer of this node, it should be disposed
dispose();
}
}
public void dispose() {
// set domain to null before removing methodElementAdapter from the
// method element so methodElement can skip handling REMOVE_ADAPTER event
// that sometimes requires new transaction to be created and causes dead-lock
//
domain = null;
EObject obj = element;
if (obj != null) {
if (methodElementAdapter != null) {
obj.eAdapters().remove(methodElementAdapter);
}
}
if(target != null) {
target.eAdapters().remove(this);
}
element = null;
}
public void setName(String newStringValue) {
ActivityNode e = getNode();
if(e != null) {
e.setName(newStringValue);
}
}
protected void handleNotification(Notification msg) {
switch(msg.getFeatureID(ActivityNode.class)) {
case UMLPackage.ACTIVITY_NODE__NAME:
if (msg.getEventType() == Notification.SET
&& getElement() instanceof BreakdownElement) {
String newName = msg.getNewStringValue();
BreakdownElement e = ((BreakdownElement) getElement());
e.setPresentationName(newName);
if (StrUtil.isBlank(e.getName())) {
e.setName(newName);
}
}
return;
case UMLPackage.ACTIVITY_NODE__INCOMING: // incoming connections
ActivityEdge link;
switch (msg.getEventType()) {
case Notification.ADD:
link = (ActivityEdge) msg.getNewValue();
addToUMA(link);
return;
case Notification.ADD_MANY:
for (Iterator iter = ((Collection) msg.getNewValue())
.iterator(); iter.hasNext();) {
addToUMA((ActivityEdge) iter.next());
}
break;
case Notification.REMOVE:
link = (ActivityEdge) msg.getOldValue();
if (link.getSource() != null) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(link.getSource());
if(nodeAdapter != null) {
nodeAdapter.removeFromUMA(link, link
.getSource(), (ActivityNode) msg.getNotifier());
}
}
break;
case Notification.REMOVE_MANY:
for (Iterator iter = ((Collection) msg.getOldValue())
.iterator(); iter.hasNext();) {
link = (ActivityEdge) iter.next();
if (link.getSource() != null) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(link.getSource());
if(nodeAdapter != null) {
nodeAdapter.removeFromUMA(link,
link.getSource(), (ActivityNode) msg.getNotifier());
}
}
}
break;
}
return;
case UMLPackage.ACTIVITY_NODE__OUTGOING:
switch (msg.getEventType()) {
case Notification.ADD:
link = (ActivityEdge) msg.getNewValue();
if (link.getTarget() != null) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(link.getTarget());
if(nodeAdapter != null) {
nodeAdapter.addToUMA(link);
}
}
break;
case Notification.ADD_MANY:
for (Iterator iter = ((Collection) msg.getNewValue())
.iterator(); iter.hasNext();) {
link = (ActivityEdge) iter.next();
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(link.getTarget());
if(nodeAdapter != null) {
nodeAdapter.addToUMA(link);
}
}
break;
case Notification.REMOVE:
link = (ActivityEdge) msg.getOldValue();
if (link.getTarget() != null) {
removeFromUMA(link, (ActivityNode) msg.getNotifier(), link
.getTarget());
}
break;
case Notification.REMOVE_MANY:
for (Iterator iter = ((Collection) msg.getOldValue())
.iterator(); iter.hasNext();) {
link = (ActivityEdge) iter.next();
if (link.getTarget() != null) {
removeFromUMA(link, (ActivityNode) msg.getNotifier(), link
.getTarget());
}
}
break;
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org.eclipse.emf.common.notify.Notification)
*/
public void notifyChanged(Notification msg) {
if (!notificationEnabled)
return;
notificationEnabled = false;
try {
handleNotification(msg);
} finally {
notificationEnabled = true;
}
}
/**
* Adds the data for the newly added node to the UMA model Subclass should
* override this method.
*
* @param position
* @param newValue
*/
protected void addToUmaModel(int position, ActivityNode node) {
//TODO: review
// if (addedNode.getGraphNode() == null) {
// // this node is readded after undo
// //
// ((NodeImpl) addedNode).basicSetObject(addedNode.getObject());
// }
}
protected void nodeAdded(int index, ActivityNode node) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
if(nodeAdapter == null) {
nodeAdapter = addNodeAdapterTo(node);
}
addToUmaModel(index, node);
if(nodeAdapter != null) {
nodeAdapter.addConsumer(this);
}
}
protected NodeAdapter addNodeAdapterTo(ActivityNode node) {
return null;
}
/**
* Removes the data for the removed node from the UMA model Subclass should
* override this method.
*
* @param node
*/
protected void removeFromUmaModel(ActivityNode node) {
}
protected void nodeRemoved(ActivityNode node) {
removeFromUmaModel(node);
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
if(nodeAdapter != null) {
nodeAdapter.removeConsumer(this);
}
}
protected boolean addToUMA(ActivityEdge link) {
if (link.getTarget() == null || link.getSource() == null)
return false;
return true;
}
protected void removeFromUMA(ActivityEdge link, ActivityNode oldSource, ActivityNode oldTarget) {
MethodElement targetElement = BridgeHelper.getMethodElement(oldTarget);
if (targetElement instanceof WorkBreakdownElement) {
// this is a direct link
// remove WorkOrder
//
NodeAdapter targetNodeAdapter = BridgeHelper.getNodeAdapter(oldTarget);
boolean notify = targetNodeAdapter != null ? targetNodeAdapter.notificationEnabled : false;
try {
if(targetNodeAdapter != null) {
targetNodeAdapter.notificationEnabled = false;
}
if (BridgeHelper.canRemoveAllPreds(link, oldSource,
oldTarget)) {
Object pred = BridgeHelper.getMethodElement(oldSource);
if(pred instanceof WorkBreakdownElement) {
WorkBreakdownElement e = (WorkBreakdownElement) BridgeHelper.getMethodElement(oldTarget);
Collection<WorkOrder> workOrders = UmaUtil.findWorkOrder(e, (WorkBreakdownElement) pred, true);
if(!workOrders.isEmpty()) {
getActionManager().doAction(IActionManager.REMOVE_MANY, e,
UmaPackage.Literals.WORK_BREAKDOWN_ELEMENT__LINK_TO_PREDECESSOR, workOrders, -1);
}
}
}
} finally {
if(targetNodeAdapter != null) {
targetNodeAdapter.notificationEnabled = notify;
}
}
} else if(oldTarget instanceof ControlNode && BridgeHelper.isSynchBar(oldTarget)) {
// get all the WorkBreakdownElementNodes that this synch bar is
// coming to and
// remove the WorkOrders with this WorkBreakdownElementNode's
// activity as predecessor from them
//
Collection<ActivityNode> actNodes = new ArrayList<ActivityNode>();
BridgeHelper.getSuccessorNodes(actNodes, oldTarget);
for (ActivityNode node : actNodes) {
WorkBreakdownElement e = (WorkBreakdownElement) BridgeHelper.getMethodElement(node);
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
boolean notify = nodeAdapter != null ? nodeAdapter.notificationEnabled : false;
try {
if(nodeAdapter != null) {
nodeAdapter.notificationEnabled = false;
}
if (BridgeHelper.canRemoveAllPreds(link, oldSource, node)) {
WorkOrder wo;
while ((wo = UmaUtil.findWorkOrder(e, BridgeHelper.getMethodElement(oldSource))) != null) {
getActionManager().doAction(IActionManager.REMOVE, e,
UmaPackage.Literals.WORK_BREAKDOWN_ELEMENT__LINK_TO_PREDECESSOR, wo, -1);
}
}
} finally {
if(nodeAdapter != null) {
nodeAdapter.notificationEnabled = notify;
}
}
}
}
}
/**
* addDefaultWorkOrder is moved from
* GraphicalDataHelper.addDefaultWorkOrder(NamedNodeImpl,
* WorkbreakdownElement) Method will set notificationEnabled flag to false
* of all adapters of type MethodElementAdapter of Successor object before
* creating a WorkOrder object. After creation of WorkOrder (Predecessor
* link) restores the notificationEnabled flag of Successor's adapters of
* type MethodElementAdapter.
*
* eg: If an Activity "actA" is extended in another CP. Base "actA" AD
* diagram is opened, and Extended "actA" AD Diagram is opened. On creating
* predecessor link between any two child activities, creates a extra link
* in Extended "actA" AD diagram, because creating workorder will notify the
* extended "actA" diagram to draw a link. To avoid duplicate links in the
* extended activity diagram, we have to set notificationEnabled flag to
* false, before creating a WorkOrder object.
*
*/
public WorkOrder addDefaultWorkOrder(ActivityNode node,
WorkBreakdownElement predBreakdownElement) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
boolean notify = nodeAdapter.notificationEnabled;
Map map = new HashMap();
MethodElement e = nodeAdapter.getElement();
List list = e.eAdapters();
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object obj = iterator.next();
if (obj instanceof MethodElementAdapter) {
NodeAdapter otherNodeAdapter = (NodeAdapter) ((MethodElementAdapter) obj)
.getNodeAdapter();
boolean predNotification = nodeAdapter.notificationEnabled;
otherNodeAdapter.notificationEnabled = false;
map.put(otherNodeAdapter, new Boolean(predNotification));
}
}
try {
nodeAdapter.notificationEnabled = false;
WorkOrder wo = UmaUtil.createDefaultWorkOrder((WorkBreakdownElement) e, predBreakdownElement, false);
getActionManager().doAction(IActionManager.ADD, e,
UmaPackage.Literals.WORK_BREAKDOWN_ELEMENT__LINK_TO_PREDECESSOR, wo, -1);
return wo;
} finally {
nodeAdapter.setNotificationEnabled(notify);
Set set = map.keySet();
for (Iterator iter = set.iterator(); iter.hasNext();) {
Object object = iter.next();
Object obj = map.get(object);
if (obj instanceof Boolean) {
boolean prednot = ((Boolean) obj).booleanValue();
((NodeAdapter) object).notificationEnabled = prednot;
}
}
}
}
public void setNotificationEnabled(boolean notify) {
notificationEnabled = notify;
}
public boolean isNotificationEnabled() {
return notificationEnabled;
}
public MethodElement getElement() {
return element;
}
public void setTarget(Notifier newTarget) {
if(newTarget == null) {
dispose();
}
super.setTarget(newTarget);
}
public BreakdownElementWrapperItemProvider getWrapper() {
return wrapper;
}
}