blob: 15036bcaeda35786e1f55aa71659a357174b1ca7 [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.Iterator;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.emf.transaction.RollbackException;
import org.eclipse.epf.diagram.core.DiagramCorePlugin;
import org.eclipse.epf.diagram.model.util.TxUtil;
import org.eclipse.epf.library.edit.IFilter;
import org.eclipse.epf.library.edit.command.ActionManager;
import org.eclipse.epf.library.edit.command.IActionManager;
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.util.DescriptorPropUtil;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.Suppression;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.uml2.uml.ActivityEdge;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.ActivityPartition;
import org.eclipse.uml2.uml.UMLPackage;
/**
* @author Phong Nguyen Le
*
* @since 1.2
*/
public class DiagramAdapter extends NodeAdapter {
private Activity baseAct;
protected IFilter filter;
private Suppression suppression;
protected long umaLastModified;
public DiagramAdapter(BreakdownElementWrapperItemProvider wrapper) {
this((Activity) TngUtil.unwrap(wrapper));
this.wrapper = wrapper;
basicSetTargetReadOnly(wrapper.isReadOnly());
}
public DiagramAdapter(Activity e) {
super(e);
// listens to change in the base activity if there is any
//
if (ProcessUtil.isExtendingOrLocallyContributing(e)) {
baseAct = (Activity) e.getVariabilityBasedOnElement();
baseAct.eAdapters().add(methodElementAdapter);
}
}
public void dispose() {
// dispose all node adapters of the child nodes
//
for (Iterator<?> iter = getNodes().iterator(); iter.hasNext();) {
ActivityNode node = (ActivityNode) iter.next();
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
if (nodeAdapter != null) {
nodeAdapter.dispose();
}
}
super.dispose();
if (baseAct != null) {
baseAct.eAdapters().remove(methodElementAdapter);
}
}
protected class ActivityAdapter extends MethodElementAdapter {
protected Collection handleNotification(Notification msg) {
Collection newNodesToRefresh = new ArrayList();
switch (msg.getFeatureID(Activity.class)) {
case UmaPackage.ACTIVITY__BREAKDOWN_ELEMENTS:
switch (msg.getEventType()) {
case Notification.ADD:
if (msg.getNewValue() instanceof TaskDescriptor) {
TaskDescriptor td = (TaskDescriptor) msg.getNewValue();
if (DescriptorPropUtil.getDesciptorPropUtil()
.getGreenParentDescriptor(td) != null) {
break;
}
}
ActivityNode node = (ActivityNode) addNode(msg
.getNewValue());
if (node != null) {
if (msg.getNotifier() == baseAct) {
BridgeHelper.getNodeAdapter(node)
.basicSetTargetReadOnly(true);
newNodesToRefresh.add(node);
}
}
break;
case Notification.REMOVE:
removeNode(msg.getOldValue());
break;
case Notification.ADD_MANY:
Collection nodes = addNodes((Collection) msg.getNewValue());
if (msg.getNotifier() == baseAct) {
for (Iterator iter = nodes.iterator(); iter.hasNext();) {
node = (ActivityNode) iter.next();
BridgeHelper.getNodeAdapter(node)
.basicSetTargetReadOnly(true);
newNodesToRefresh.add(node);
}
}
break;
case Notification.REMOVE_MANY:
removeNodes((Collection) msg.getOldValue());
break;
case Notification.MOVE:
moveNode(msg.getNewValue());
break;
case Notification.SET:
replaceNode(msg.getOldValue(), msg.getNewValue());
break;
}
break;
default:
return super.handleNotification(msg);
}
return newNodesToRefresh;
}
}
protected void handleNotification(Notification msg) {
switch(msg.getFeatureID(org.eclipse.uml2.uml.Activity.class)) {
case UMLPackage.ACTIVITY__NODE:
Collection collection;
switch (msg.getEventType()) {
case Notification.ADD:
nodeAdded(msg.getPosition(), (ActivityNode) msg
.getNewValue());
return;
case Notification.REMOVE:
nodeRemoved((ActivityNode) msg.getOldValue());
return;
case Notification.ADD_MANY:
collection = (Collection) msg.getNewValue();
for (Iterator iter = collection.iterator(); iter
.hasNext();) {
ActivityNode node = (ActivityNode) iter.next();
nodeAdded(msg.getPosition(), node);
}
return;
case Notification.REMOVE_MANY:
collection = (Collection) msg.getOldValue();
for (Iterator iter = collection.iterator(); iter
.hasNext();) {
nodeRemoved((ActivityNode) iter.next());
}
return;
}
}
super.handleNotification(msg);
}
protected void replaceNode(Object oldElement, Object newElement) {
}
protected MethodElementAdapter createMethodElementAdapter() {
return new ActivityAdapter();
}
protected final void populateLinks() {
populateLinks(getNodes());
}
protected void populateLinks(List<ActivityNode> selectedNodes) {
// fill outgoing/incoming connection lists of all nodes
//
int size = selectedNodes.size();
boolean[] notifies = new boolean[size];
try {
// disable notification for all nodes in this diagram to avoid
// unwanted concurrent modification of their connection list
//
for (int i = 0; i < size; i++) {
ActivityNode node = selectedNodes.get(i);
notifies[i] = node.eDeliver();
node.eSetDeliver(false);
}
for (ActivityNode node : selectedNodes) {
populateLinks(node, false);
}
} finally {
// restore notification flag
//
for (int i = 0; i < size; i++) {
selectedNodes.get(i).eSetDeliver(notifies[i]);
}
}
}
protected List getNodes() {
org.eclipse.uml2.uml.Activity diagram = getDiagram();
return diagram != null ? getDiagram().getNodes() : Collections.emptyList();
}
protected org.eclipse.uml2.uml.Activity getDiagram() {
return (org.eclipse.uml2.uml.Activity) getTarget();
}
protected boolean removeNode(Object obj) {
if (!TngUtil.isInstanceOf(getBreakdownElementTypes(), obj))
return false;
ActivityNode node = BridgeHelper.findNode(getDiagram(), obj);
if (node == null)
return false;
for (Iterator iter = node.getOutgoings().iterator(); iter.hasNext();) {
ActivityEdge link = (ActivityEdge) iter.next();
link.setTarget(null);
}
for (Iterator iter = node.getIncomings().iterator(); iter.hasNext();) {
ActivityEdge link = (ActivityEdge) iter.next();
link.setSource(null);
}
node.getOutgoings().clear();
node.getIncomings().clear();
getNodes().remove(node);
return true;
}
protected void removeNodes(Collection collection) {
for (Iterator iter = collection.iterator(); iter.hasNext();) {
removeNode(iter.next());
}
}
protected ActivityNode addNode(Object obj) {
ActivityNode node = addNode(getNodes(), obj);
if (node == null)
return node;
populateLinks(node, true);
return node;
}
protected Collection addNodes(Collection collection) {
List nodes = new ArrayList();
for (Iterator iter = collection.iterator(); iter.hasNext();) {
addNode(nodes, iter.next());
}
// use addAll() to avoid unnecessary notifications
//
getNodes().addAll(nodes);
return nodes;
}
/**
* In Process WBS, if breakdownelement is moved up or down, diagram should
* be updated accordingly. Sub-class should override this method if diagram
* needs update on move.
*
* @param newValue
*/
public void moveNode(Object oldValue) {
}
/**
* Populates the incoming/outgoing links of the given node
*
* @param node
*/
protected void populateLinks(ActivityNode node, boolean disableNotification) {
// int size = 0;
// boolean[] notifies = null;
// try {
// if (disableNotification) {
// size = getNodes().size();
// notifies = new boolean[size];
// // disable notification for all nodes in this diagram to avoid
// // unwanted concurrent modification of their connection list
// //
// for (int i = 0; i < size; i++) {
// Node child = ((Node) getNodes().get(i));
// notifies[i] = child.eDeliver();
// child.eSetDeliver(false);
// }
// }
//
// GraphNode graphNode = node.getGraphNode();
// if (graphNode != null) {
// GraphicalDataHelper.fillConnections(node, graphNode);
// }
// } finally {
// if (disableNotification) {
// // restore notification flag
// //
// for (int i = 0; i < size; i++) {
// ((EObject) getNodes().get(i)).eSetDeliver(notifies[i]);
// }
// }
// }
}
/**
* Creates new node for this diagram for the given MethodElement.
*
* @param e
* @return
*/
protected ActivityNode toNode(MethodElement e) {
ActivityNode node = newNode(e);
if (node == null)
return null;
initializeNode(node, e);
return node;
}
protected void initializeNodeAdapter(NodeAdapter nodeAdapter) {
nodeAdapter.setEditingDomain(domain);
nodeAdapter.actionManager = actionManager;
}
private void initializeNode(ActivityNode node, MethodElement e) {
String name = BridgeHelper.getNodeName(e);
node.setName(name);
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
if (nodeAdapter != null && nodeAdapter.getElement() != e) {
nodeAdapter.dispose();
nodeAdapter = null;
}
if (nodeAdapter == null) {
nodeAdapter = createNodeAdapter(e);
initializeNodeAdapter(nodeAdapter);
node.eAdapters().add(nodeAdapter);
}
}
protected NodeAdapter createNodeAdapter(MethodElement e) {
return null;
}
protected ActivityNode newNode(MethodElement e) {
return null;
}
/**
* Creates a new node for the given method element <code>obj</code> and
* add it to the given collection of nodes
*
* @param nodes
* @param obj
* method element
* @return
*/
protected ActivityNode addNode(Collection nodes, Object obj) {
if (TngUtil.isInstanceOf(getBreakdownElementTypes(), obj)) {
ActivityNode node = toNode((MethodElement) obj);
if (node != null) {
nodes.add(node);
return node;
}
}
return null;
}
protected List getBreakdownElementTypes() {
return Collections.singletonList(BreakdownElement.class);
}
public Activity getActivity() {
return (Activity) element;
}
protected void removeFromUmaModel(ActivityNode removedNode) {
Object e;
if ((e = BridgeHelper.getMethodElement(removedNode)) instanceof BreakdownElement) {
getActionManager().doAction(IActionManager.REMOVE, getActivity(),
UmaPackage.Literals.ACTIVITY__BREAKDOWN_ELEMENTS, e, -1);
}
super.removeFromUmaModel(removedNode);
}
protected void extractChildren(ITreeItemContentProvider adapter, Object object, Collection children) {
// disable rollup before getting the children
//
boolean oldRolledUp = false;
if(adapter instanceof BSActivityItemProvider) {
BSActivityItemProvider itemProvider = (BSActivityItemProvider)adapter;
oldRolledUp = itemProvider.isRolledUp();
itemProvider.basicSetRolledUp(false);
}
else if(adapter instanceof IBSItemProvider){
IBSItemProvider itemProvider = (IBSItemProvider)adapter;
oldRolledUp = itemProvider.isRolledUp();
itemProvider.setRolledUp(false);
}
try {
// filter out the suppressed elements
//
for (Iterator iter = adapter.getChildren(object).iterator(); iter.hasNext();) {
Object child = iter.next();
if(!getSuppression().isSuppressed(child)) {
children.add(child);
}
}
// don't filter suppressed elements
//
//children.addAll(adapter.getChildren(object));
}
finally {
// restore the rolled-up flag
//
if(adapter instanceof IBSItemProvider) {
((IBSItemProvider)adapter).setRolledUp(oldRolledUp);
}
}
}
public Suppression getSuppression() {
return suppression;
}
public void setSuppression(Suppression suppression) {
this.suppression = suppression;
}
protected void updateView(Collection<?> selectedNodes) throws InterruptedException, RollbackException {
updateView(getView(), selectedNodes);
}
private static boolean isWorkBreakdownElementType(View node) {
// hack by using the visual IDs defined in AD model
// StructuredActivityNodeEditPart 1007 Activity
// StructuredActivityNode2EditPart 1010 Phase
// StructuredActivityNode3EditPart 1011 Iteration
// ActivityParameterNodeEditPart 1009 TaskDescriptor
// ActivityParameterNode2EditPart 1012 Milestone
//
String type = node.getType();
return type != null && ("1007".equals(type) //$NON-NLS-1$
|| "1010".equals(type) //$NON-NLS-1$
|| "1011".equals(type) //$NON-NLS-1$
|| "1009".equals(type) //$NON-NLS-1$
|| "1012".equals(type)); //$NON-NLS-1$
}
private static void updateView(View view, Collection<?> selectedNodes) {
// show the selected nodes and hide all the other
//
for (Iterator<?> iter = view.getChildren().iterator(); iter.hasNext();) {
View node = (View) iter.next();
if(selectedNodes.contains(node.getElement())) {
NodeAdapter adapter = BridgeHelper.getNodeAdapter(node.getElement());
if(adapter != null) {
adapter.updateView();
}
// if(!node.isVisible()) {
node.setVisible(true);
// }
}
else {
if(node.getElement() instanceof ActivityNode) {
if(node.isVisible()) {
node.setVisible(false);
}
}
else if(node.getElement() instanceof ActivityPartition) {
updateView(node, selectedNodes);
}
// this is a work around to not show any work breakdown element
// node that does not have any model reference (View.element)
// GMF returns the container view's element if the child node's element
// is not set. Therefore, if the child node is shown, it will be displayed
// as a node of parent activity. Deleting this node in editor will delete
// the parent activity as result.
//
else if(isWorkBreakdownElementType(node) && (!node.isSetElement() || node.getElement() == view.getElement())) {
if(node.isVisible()) {
node.setVisible(false);
}
}
else {
if(!node.isVisible()) {
node.setVisible(true);
}
}
}
}
}
protected void updateEdges(Collection selectedNodes) throws InterruptedException, RollbackException {
for (Iterator iter = getView().getChildren().iterator(); iter.hasNext();) {
View node = (View) iter.next();
if(selectedNodes.contains(node.getElement())) {
NodeAdapter adapter = BridgeHelper.getNodeAdapter(node.getElement());
adapter.updateView();
// if(!node.isVisible()) {
node.setVisible(true);
setEdgeVisibility(node, true);
// }
}
else {
if(node.getElement() instanceof ActivityNode) {
if(node.isVisible()) {
setEdgeVisibility(node, false);
}
}
else {
if(!node.isVisible()) {
node.setVisible(true);
setEdgeVisibility(node, true);
}
}
}
}
}
private void setEdgeVisibility(View view, boolean visibility){
Diagram diagram = view.getDiagram();
for (Iterator iterator = diagram.getEdges().iterator(); iterator
.hasNext();) {
Edge edge = (Edge) iterator.next();
if(edge.getSource() == view || edge.getTarget() == view){
if(visibility){
view.setVisible(true);
}
edge.setVisible(visibility);
}
}
}
/**
* Populates the diagram with the data from the UMA model. Subclass should
* override this method.
*/
public void populateDiagram() {
boolean notify = notificationEnabled;
try {
notificationEnabled = false;
final List<ActivityNode> selectedNodes = new ArrayList<ActivityNode>();
org.eclipse.uml2.uml.Activity diagram = getDiagram();
TxUtil.runInTransaction(diagram, new Runnable() {
public void run() {
selectedNodes.addAll(populateNodes());
populateLinks(selectedNodes);
}
});
// add this diagram to the consumer list of all nodes so they will not
// be disposed
// before this diagram.
//
for (ActivityNode node : selectedNodes) {
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(node);
if(nodeAdapter != null) {
nodeAdapter.addConsumer(this);
}
}
TxUtil.runInTransaction(diagram, new Runnable() {
public void run() {
try {
updateEdges(selectedNodes);
updateView(selectedNodes);
} catch(Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
}
});
}
catch(Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
finally {
notificationEnabled = notify;
}
}
protected Collection populateNodes() {
return Collections.EMPTY_LIST;
}
public void setFilter(IFilter filter) {
this.filter = filter;
}
public IActionManager getActionManager() {
if(actionManager == null) {
actionManager = new ActionManager() {
public boolean doAction(int actionType, EObject object, EStructuralFeature feature, Object value, int index) {
boolean ret = super.doAction(actionType, object, feature, value, index);
if(ret) {
umaLastModified = System.currentTimeMillis();
}
return ret;
}
};
}
return actionManager;
}
public long getUmaLastModified() {
return umaLastModified;
}
public IFilter getFilter() {
return filter;
}
}