| //------------------------------------------------------------------------------ |
| // 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.diagram.model.impl; |
| |
| import java.text.MessageFormat; |
| 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.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.edit.provider.ITreeItemContentProvider; |
| import org.eclipse.epf.diagram.model.Diagram; |
| import org.eclipse.epf.diagram.model.DiagramResources; |
| import org.eclipse.epf.diagram.model.Link; |
| import org.eclipse.epf.diagram.model.ModelFactory; |
| import org.eclipse.epf.diagram.model.ModelPackage; |
| import org.eclipse.epf.diagram.model.NamedNode; |
| import org.eclipse.epf.diagram.model.Node; |
| import org.eclipse.epf.diagram.model.TypedNode; |
| import org.eclipse.epf.diagram.model.util.GraphicalDataHelper; |
| import org.eclipse.epf.diagram.model.util.GraphicalDataManager; |
| import org.eclipse.epf.diagram.model.util.IDiagramChangeListener; |
| import org.eclipse.epf.library.edit.IFilter; |
| 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.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.GraphNode; |
| import org.eclipse.epf.uma.MethodElement; |
| import org.eclipse.epf.uma.SemanticModelBridge; |
| import org.eclipse.epf.uma.SimpleSemanticModelElement; |
| import org.eclipse.epf.uma.UmaPackage; |
| |
| |
| /** |
| * <!-- begin-user-doc --> An implementation of the model object '<em><b>Diagram</b></em>'. |
| * <!-- end-user-doc --> |
| * <p> |
| * </p> |
| * |
| * @generated |
| */ |
| public class DiagramImpl extends NodeContainerImpl implements Diagram { |
| |
| private boolean newDiagram; |
| |
| /** |
| * <!-- begin-user-doc --> <!-- end-user-doc --> |
| * @generated |
| */ |
| protected DiagramImpl() { |
| super(); |
| } |
| |
| /** |
| * <!-- begin-user-doc --> <!-- end-user-doc --> |
| * @generated |
| */ |
| @Override |
| protected EClass eStaticClass() { |
| return ModelPackage.Literals.DIAGRAM; |
| } |
| |
| // -------------------// |
| // Start custom code // |
| // -------------------// |
| |
| protected class ActivityAdapter extends TransactionalNodeLink implements |
| IDiagramChangeListener { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.diagram.model.util.IDiagramChangeListener#getDiagram() |
| */ |
| public Diagram getDiagram() { |
| return DiagramImpl.this; |
| } |
| |
| @Override |
| protected void handleNotification(Notification msg) { |
| switch (msg.getFeatureID(Activity.class)) { |
| case UmaPackage.ACTIVITY__BREAKDOWN_ELEMENTS: |
| switch (msg.getEventType()) { |
| case Notification.ADD: |
| Node node = (Node) addNode(msg.getNewValue()); |
| if (node != null) { |
| if (msg.getNotifier() == baseAct) { |
| node.setReadOnly(true); |
| } |
| } |
| 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 = (NodeImpl) iter.next(); |
| node.setReadOnly(true); |
| } |
| } |
| break; |
| case Notification.REMOVE_MANY: |
| removeNodes((Collection) msg.getOldValue()); |
| break; |
| case Notification.MOVE: |
| moveNode(msg.getNewValue(), msg.getPosition(), msg.getOldValue()); |
| break; |
| } |
| break; |
| } |
| } |
| |
| } |
| |
| protected IDiagramChangeListener diagramChangeListener; |
| |
| private Activity baseAct; |
| |
| private Object diagramAdapter = new AdapterImpl() { |
| /* |
| * (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 { |
| //Activity act = (Activity) getObject(); |
| switch (msg.getFeatureID(Diagram.class)) { |
| case ModelPackage.DIAGRAM__NODES: |
| // System.out.println(".notifyChanged(): index=" + |
| // msg.getPosition()); |
| Collection collection; |
| switch (msg.getEventType()) { |
| case Notification.ADD: |
| nodeAdded(msg.getPosition(), (Node) msg |
| .getNewValue()); |
| return; |
| case Notification.REMOVE: |
| nodeRemoved((Node) msg.getOldValue()); |
| return; |
| case Notification.ADD_MANY: |
| collection = (Collection) msg.getNewValue(); |
| for (Iterator iter = collection.iterator(); iter |
| .hasNext();) { |
| Node node = (Node) iter.next(); |
| nodeAdded(msg.getPosition(), node); |
| } |
| |
| return; |
| case Notification.REMOVE_MANY: |
| collection = (Collection) msg.getOldValue(); |
| for (Iterator iter = collection.iterator(); iter |
| .hasNext();) { |
| nodeRemoved((Node) iter.next()); |
| } |
| return; |
| } |
| |
| } |
| } finally { |
| notificationEnabled = true; |
| } |
| } |
| }; |
| |
| protected Node addNode(Object obj) { |
| Node node = addNode(getNodes(), obj); |
| if (node == null) |
| return node; |
| populateLinks(node, true); |
| return node; |
| } |
| |
| protected Node addNode(Collection nodes, Object obj) { |
| if (TngUtil.isInstanceOf(getBreakdownElementTypes(), obj)) { |
| Node node = toNode((MethodElement) obj); |
| if (node != null) { |
| nodes.add(node); |
| return node; |
| } |
| } |
| return null; |
| } |
| |
| 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; |
| } |
| |
| /** |
| * @param obj |
| */ |
| protected boolean removeNode(Object obj) { |
| if (!TngUtil.isInstanceOf(getBreakdownElementTypes(), obj)) |
| return false; |
| |
| Node node = GraphicalDataHelper.findNode(this, obj); |
| if (node == null) |
| return false; |
| |
| for (Iterator iter = node.getOutgoingConnections().iterator(); iter |
| .hasNext();) { |
| Link link = (Link) iter.next(); |
| link.setTarget(null); |
| } |
| |
| for (Iterator iter = node.getIncomingConnections().iterator(); iter |
| .hasNext();) { |
| Link link = (Link) iter.next(); |
| link.setSource(null); |
| } |
| node.getOutgoingConnections().clear(); |
| node.getIncomingConnections().clear(); |
| |
| getNodes().remove(node); |
| return true; |
| } |
| |
| protected void removeNodes(Collection collection) { |
| for (Iterator iter = collection.iterator(); iter.hasNext();) { |
| removeNode(iter.next()); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.diagram.model.Diagram#getUMADiagram() |
| */ |
| public org.eclipse.epf.uma.Diagram getUMADiagram() { |
| return (org.eclipse.epf.uma.Diagram) getGraphNode(); |
| } |
| |
| protected Class getDiagramChangeListenerType() { |
| return IDiagramChangeListener.class; |
| } |
| |
| protected List getBreakdownElementTypes() { |
| return Collections.singletonList(BreakdownElement.class); |
| } |
| |
| protected int getType() { |
| return -1; |
| } |
| |
| protected void nodeAdded(int index, Node node) { |
| addToUmaModel(index, node); |
| node.addConsumer(this); |
| } |
| |
| protected void nodeRemoved(Node node) { |
| removeFromUmaModel(node); |
| node.removeConsumer(this); |
| } |
| |
| public boolean isNew() { |
| return this.newDiagram; |
| } |
| |
| public void setNew(boolean n) { |
| this.newDiagram = n; |
| } |
| |
| /** |
| * NOTE: this method is re-entrant, make sure to handle the data correctly to avoid memory leak and data corruption |
| * |
| * @param newObject |
| * must be an Activity |
| */ |
| public void setObject(Object newObject) { |
| if (newObject instanceof BreakdownElementWrapperItemProvider |
| && ((BreakdownElementWrapperItemProvider) newObject) |
| .isReadOnly()) { |
| wrapper = (BreakdownElementWrapperItemProvider) newObject; |
| setReadOnly(true); |
| } |
| newObject = TngUtil.unwrap(newObject); |
| |
| object = newObject; |
| |
| // add diagram change listener to the linked object. Remove the old |
| // listener if there is any. |
| // But first keep the old listener to help find the UMA diagram of the |
| // activity quickly. |
| // |
| Activity e = (Activity) newObject; |
| if(ProcessUtil.isExtendingOrLocallyContributing(e)) { |
| baseAct = (Activity) e.getVariabilityBasedOnElement(); |
| } |
| baseAct = null; |
| |
| if(newObject == null) { |
| return; |
| } |
| |
| // set the UMA diagram for this diagram |
| // |
| if(isGraphicalDataRequired()) { |
| graphNode = GraphicalDataManager.getInstance().getUMADiagram(e, |
| getType(), false); |
| // set the flag to indicate this is a new diagram or not |
| if (graphNode == null) { |
| graphNode = GraphicalDataManager.getInstance().getUMADiagram(e, |
| getType(), true); |
| setNew(true); |
| } |
| } |
| |
| if(!e.eAdapters().contains(diagramChangeListener)) { |
| e.eAdapters().add(diagramChangeListener); |
| } |
| if (baseAct != null && !baseAct.eAdapters().contains(diagramChangeListener)) { |
| baseAct.eAdapters().add(diagramChangeListener); |
| } |
| |
| populateDiagram(); |
| |
| if(!eAdapters().contains(diagramAdapter)) { |
| this.eAdapters().add((Adapter) diagramAdapter); |
| } |
| |
| } |
| |
| /** |
| * Populates the diagram with the data from the UMA model. Subclass should |
| * override this method. |
| */ |
| protected void populateDiagram() { |
| populateNodes(); |
| populateLinks(); |
| |
| // add this diagram to the consumer list of all nodes so they will not |
| // be disposed |
| // before this diagram. |
| // |
| for (Iterator iter = getNodes().iterator(); iter.hasNext();) { |
| NodeImpl node = (NodeImpl) iter.next(); |
| node.addConsumer(this); |
| } |
| } |
| |
| /** |
| * Populates the incoming/outgoing links of the given node |
| * |
| * @param node |
| */ |
| protected void populateLinks(Node 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]); |
| } |
| } |
| } |
| } |
| |
| protected void populateNodes() { |
| org.eclipse.epf.uma.Diagram diagram = getUMADiagram(); |
| if(diagram != null) { |
| List typedNodes = new ArrayList(); |
| for (Iterator iter = diagram.getContained().iterator(); iter.hasNext();) { |
| Object element = iter.next(); |
| int type = getType(element); |
| if (type > 0) { |
| TypedNode node = ModelFactory.eINSTANCE.createTypedNode(); |
| node.setType(type); |
| node.setObject(element); |
| typedNodes.add(node); |
| } |
| } |
| getNodes().addAll(typedNodes); |
| } |
| } |
| |
| private static int getType(Object obj) { |
| if (obj instanceof GraphNode) { |
| GraphNode node = (GraphNode) obj; |
| SemanticModelBridge modelBridge = node.getSemanticModel(); |
| if (modelBridge instanceof SimpleSemanticModelElement) { |
| String type = ((SimpleSemanticModelElement) modelBridge) |
| .getTypeInfo(); |
| if (GraphicalDataHelper.GRAPH_NODE_SYNCH_BAR.equals(type)) { |
| return TypedNode.SYNCH_BAR; |
| } else if (GraphicalDataHelper.GRAPH_NODE_DECISION.equals(type)) { |
| return TypedNode.DECISION; |
| } else if (GraphicalDataHelper.GRAPH_NODE_END.equals(type)) { |
| return TypedNode.END; |
| } else if (GraphicalDataHelper.GRAPH_NODE_START.equals(type)) { |
| return TypedNode.START; |
| } else if (GraphicalDataHelper.GRAPH_NODE_FREE_TEXT |
| .equals(type)) { |
| return TypedNode.FREE_TEXT; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| protected void populateLinks() { |
| // fill outgoing/incoming connection lists of all nodes |
| // |
| int size = getNodes().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++) { |
| Node node = ((Node) getNodes().get(i)); |
| notifies[i] = node.eDeliver(); |
| node.eSetDeliver(false); |
| } |
| for (Iterator iter = getNodes().iterator(); iter.hasNext();) { |
| Node node = (Node) iter.next(); |
| populateLinks(node, false); |
| } |
| } finally { |
| // restore notification flag |
| // |
| for (int i = 0; i < size; i++) { |
| ((EObject) getNodes().get(i)).eSetDeliver(notifies[i]); |
| } |
| } |
| |
| } |
| |
| /** |
| * Removes the data for the removed node from the UMA model Subclass should |
| * override this method. |
| * |
| * @param removedNode |
| */ |
| protected void removeFromUmaModel(Node removedNode) { |
| Activity act = (Activity) getObject(); |
| if (removedNode.getObject() instanceof BreakdownElement) { |
| act.getBreakdownElements().remove(removedNode.getObject()); |
| } |
| |
| if(getUMADiagram() != null) { |
| getUMADiagram().getContained().remove(removedNode.getGraphNode()); |
| } |
| } |
| |
| /** |
| * 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, Node addedNode) { |
| |
| if (addedNode.getGraphNode() == null) { |
| // this node is readded after undo |
| // |
| ((NodeImpl) addedNode).basicSetObject(addedNode.getObject()); |
| } |
| |
| if(getUMADiagram() != null) { |
| getUMADiagram().getContained().add(addedNode.getGraphNode()); |
| } |
| } |
| |
| /** |
| * Creates new node for this diagram for the given MethodElement. |
| * |
| * @param e |
| * @return |
| */ |
| protected Node toNode(MethodElement e) { |
| Node node = newNode(); |
| if (node == null) |
| return null; |
| node.setUMADiagram(getUMADiagram()); |
| node.setDiagram(this); |
| node.setObject(e); |
| return node; |
| } |
| |
| protected Node newNode() { |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.diagram.model.Node#getMethodElementAdapterType() |
| */ |
| public Class getMethodElementAdapterType() { |
| return getDiagramChangeListenerType(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.diagram.model.impl.NodeImpl#dispose() |
| */ |
| protected void dispose() { |
| if (diagramChangeListener != null) { |
| Activity e = (Activity) getObject(); |
| if (baseAct != null) { |
| baseAct.eAdapters().remove(diagramChangeListener); |
| } |
| if(e != null) { |
| e.eAdapters().remove(diagramChangeListener); |
| } |
| } |
| |
| super.dispose(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.diagram.model.Diagram#setDefaultName(org.eclipse.epf.diagram.model.NamedNode) |
| */ |
| public void setDefaultName(NamedNode newNode) { |
| MethodElement obj = (MethodElement) newNode.getObject(); |
| int classID = obj.eClass().getClassifierID(); |
| Activity act = (Activity) getObject(); |
| ArrayList siblings = new ArrayList(); |
| for (Iterator iter = act.getBreakdownElements().iterator(); iter |
| .hasNext();) { |
| BreakdownElement e = (BreakdownElement) iter.next(); |
| if (e.eClass().getClassifierID() == classID) { |
| siblings.add(e); |
| } |
| } |
| String baseName = MessageFormat |
| .format( |
| DiagramResources.defaultBaseName, new Object[] { TngUtil.getTypeText(obj.eClass().getName()) }); |
| TngUtil.setDefaultName(siblings, obj, baseName); |
| newNode.setName(obj.getName()); |
| } |
| |
| protected void extractChildren(ITreeItemContentProvider adapter, Object object, Collection children, |
| boolean filterSuppressed) { |
| // 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 |
| // |
| if (adapter != null) { |
| if(filterSuppressed){ |
| for (Iterator iter = adapter.getChildren(object).iterator(); iter.hasNext();) { |
| Object child = iter.next(); |
| if(!getSuppression().isSuppressed(child)) { |
| children.add(child); |
| } |
| } |
| }else{ |
| // 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; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.epf.diagram.model.Diagram#setFilter(com.ibm.library.edit.IFilter) |
| */ |
| public void setFilter(IFilter filter) { |
| this.filter = filter; |
| } |
| |
| /** |
| * 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 |
| * @param newposition int |
| * @param oldPosition Object(Integer) |
| */ |
| public void moveNode(Object movedObject, int position, Object oldPosition) { |
| } |
| |
| public boolean isGraphicalDataRequired() { |
| return graphicalDataRequired; |
| } |
| |
| public void setGraphicalDataRequired(boolean graphicalDataRequired) { |
| this.graphicalDataRequired = graphicalDataRequired; |
| } |
| |
| public IFilter getFilter() { |
| return filter; |
| } |
| |
| public void setWrapper(BreakdownElementWrapperItemProvider wrapper) { |
| this.wrapper = wrapper; |
| } |
| |
| public Collection getChildren() { |
| return Collections.EMPTY_LIST; |
| } |
| |
| private Suppression suppression; |
| |
| protected BreakdownElementWrapperItemProvider wrapper; |
| |
| protected IFilter filter; |
| |
| private boolean graphicalDataRequired = true; |
| |
| } // DiagramImpl |