blob: 558b956fcbeafa45697f0a66b97012bcf45d372e [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
//------------------------------------------------------------------------------
/**
*
*/
package org.eclipse.epf.diagram.core.actions;
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 org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.edit.command.CopyCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.epf.diagram.core.DiagramCorePlugin;
import org.eclipse.epf.diagram.core.DiagramCoreResources;
import org.eclipse.epf.diagram.core.bridge.BridgeHelper;
import org.eclipse.epf.diagram.core.bridge.DiagramAdapter;
import org.eclipse.epf.diagram.core.bridge.NodeAdapter;
import org.eclipse.epf.diagram.core.part.AbstractDiagramEditor;
import org.eclipse.epf.diagram.core.part.util.DiagramEditorUtil;
import org.eclipse.epf.diagram.core.services.DiagramHelper;
import org.eclipse.epf.diagram.core.services.DiagramService;
import org.eclipse.epf.diagram.model.impl.NodeImpl;
import org.eclipse.epf.diagram.model.util.TxUtil;
import org.eclipse.epf.library.edit.util.IDiagramManager;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.VariabilityType;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.Command;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.services.editpart.EditPartService;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.uml2.uml.ActivityEdge;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.ObjectNode;
import org.eclipse.uml2.uml.StructuredActivityNode;
/**
* Action to refresh the latest changes from base activity diagram into
* extend's Activity diagram. Action will keep the existing immediate children's
* information of extend diagram, only refresh the base diagram's related information.
*
* @author Shashidhar Kannoori
* @author Phong Nguyen Le
*/
public class RefreshFromBaseAction implements IObjectActionDelegate {
private EditPart editPart;
private IWorkbenchPart targetPart;
/**
*
*/
public RefreshFromBaseAction() {
}
/* (non-Javadoc)
* @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
*/
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
this.targetPart = targetPart;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
public void run(IAction action) {
refreshFromBaseCommand.execute();
}
/* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IAction action, ISelection selection) {
editPart = null;
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
if (structuredSelection.size() == 1
&& structuredSelection.getFirstElement() instanceof EditPart) {
editPart = (EditPart) structuredSelection
.getFirstElement();
}
}
if(editPart != null){
action.setChecked(false);
// Check if diagram readonly.
if(editPart instanceof DiagramEditPart){
if(!((DiagramEditPart)editPart).isEditModeEnabled()){
action.setEnabled(false);
return;
}
}
// Checked variability
Diagram diagram = (Diagram)editPart.getModel();
EObject model = diagram.getElement();
Activity e = null;
if(model instanceof org.eclipse.uml2.uml.Activity){
e = (Activity)BridgeHelper.getMethodElement((EModelElement)model);
}else if(model instanceof org.eclipse.epf.diagram.model.Diagram){
e = (Activity)((org.eclipse.epf.diagram.model.Diagram)model).getLinkedElement();
}
if(e != null){
if(e instanceof Activity){
if(((Activity)e).getVariabilityBasedOnElement() == null
|| (((Activity)e).getVariabilityBasedOnElement() != null
&& ((Activity)e).getVariabilityType() != VariabilityType.EXTENDS)){
action.setEnabled(false);
return;
}
}
}
}else{
action.setEnabled(false);
}
}
/**
* Refresh base from previous graphical editor code.
* TODO: handle consumer (set)
*
*/
private Command refreshFromBaseCommand = new Command(DiagramCoreResources.AbstractDiagramEditorrefreshfrombase) { //$NON-NLS-1$
private ArrayList oldContent = new ArrayList();
public void execute() {
Diagram diagram = (Diagram) editPart.getModel();
EditPart parent = editPart.getParent();
// back up old diagram content
//
oldContent.clear();
oldContent.addAll(diagram.getPersistedChildren());
boolean refreshed = //DiagramHelper.refreshFromBase(diagram);
refreshFromBase(diagram);
if(!refreshed) return;
if (editPart.isActive()) {
editPart.deactivate();
}
//diagram.removeConsumer(this);
//createEditPart();
editPart = (EditPart)EditPartService.getInstance().createGraphicEditPart(diagram);
editPart.setParent(parent);
parent.getViewer().setContents(editPart);
}
public void undo() {
Diagram diagram = (Diagram) editPart.getModel();
diagram.getChildren().clear();
diagram.getChildren().addAll(oldContent);
if (editPart.isActive()) {
editPart.deactivate();
}
//diagram.removeConsumer(this);
editPart = (EditPart)EditPartService.getInstance().createGraphicEditPart(diagram);
getGraphicalViewer().setContents(editPart);
editPart.activate();
}
};
private GraphicalViewer getGraphicalViewer(){
return (GraphicalViewer)editPart.getRoot().getViewer();
}
public boolean refreshFromBase(final Diagram diagram) {
final boolean[] resultHolder = new boolean[1];
try {
TxUtil.runInTransaction(diagram, new Runnable() {
public void run() {
resultHolder[0] = doRefreshFromBase(diagram);
}
});
} catch (Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
return resultHolder[0];
}
public boolean refreshFromBase(final Diagram diagram, final Activity activity) {
final boolean[] resultHolder = new boolean[1];
try {
TxUtil.runInTransaction(diagram, new Runnable() {
public void run() {
resultHolder[0] = doRefreshFromBase(diagram, activity);
}
});
} catch (Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
return resultHolder[0];
}
private static interface IDiagramAssociationHelper {
/**
* Gets the {@link MethodElement} that the given {@link Node} represents.
*
* @param node
* @param resourceSet the resource set of the library
* @return
*/
MethodElement getMethodElement(Node node, ResourceSet resourceSet);
/**
* Finds in the given diagram the node that represents the given {@link MethodElement}.
*
* @param diagram
* @param e
* @return
*/
Node findNode(Diagram diagram, MethodElement e);
/**
* Re-associates activity nodes in the base diagram copy with corresponding
* locally contributors or replacers if there is any.
*
* @param activity
* @param copyOfBaseDiagram
*/
void reassociate(Activity activity, Diagram copyOfBaseDiagram);
void addNodeModels(EObject diagramModel, Collection<?> nodeModels);
void addEdgeModels(EObject diagramModel, Collection<?> edgeModels);
void removeNodeModel(EObject diagramModel, EObject nodeModel);
void removeEdgeModel(EObject diagramModel, EObject edgeModel);
Collection<?> getNodeModels(EObject element);
Collection<?> getEdgeModels(EObject element);
}
private static final IDiagramAssociationHelper ADAssociationHelper = new IDiagramAssociationHelper() {
public Node findNode(Diagram diagram, MethodElement e) {
return DiagramHelper.findNode(diagram, e);
}
public MethodElement getMethodElement(Node node, ResourceSet resourceSet) {
EObject umlObject = node.getElement();
if (umlObject instanceof StructuredActivityNode
|| umlObject instanceof ObjectNode) {
MethodElement e = BridgeHelper
.getMethodElement((ActivityNode) umlObject);
if (e == null && resourceSet != null) {
// base diagram is not open, try to get from
// annotation
//
e = BridgeHelper
.getMethodElementFromAnnotation(
(EModelElement) umlObject, resourceSet);
}
return e;
}
return null;
}
public void reassociate(Activity activity, Diagram copyOfBaseDiagram) {
DiagramHelper.reassociate(activity, copyOfBaseDiagram);
}
public void addEdgeModels(EObject diagramModel, Collection<?> edgeModels) {
if(!(diagramModel instanceof org.eclipse.uml2.uml.Activity)) {
return;
}
DiagramAdapter diagramAdapter = BridgeHelper.getDiagramAdapter(diagramModel);
boolean oldNotify = false;
if(diagramAdapter != null) {
oldNotify = diagramAdapter.isNotificationEnabled();
diagramAdapter.setNotificationEnabled(false);
}
try {
((org.eclipse.uml2.uml.Activity) diagramModel).getEdges().addAll((Collection<? extends ActivityEdge>) edgeModels);
}
finally {
if(diagramAdapter != null) {
diagramAdapter.setNotificationEnabled(oldNotify);
}
}
}
public void addNodeModels(EObject diagramModel, Collection<?> nodeModels) {
if(!(diagramModel instanceof org.eclipse.uml2.uml.Activity)) {
return;
}
DiagramAdapter diagramAdapter = BridgeHelper.getDiagramAdapter(diagramModel);
boolean oldNotify = false;
if(diagramAdapter != null) {
oldNotify = diagramAdapter.isNotificationEnabled();
diagramAdapter.setNotificationEnabled(false);
}
try {
((org.eclipse.uml2.uml.Activity) diagramModel).getNodes().addAll((Collection<? extends ActivityNode>) nodeModels);
}
finally {
if(diagramAdapter != null) {
diagramAdapter.setNotificationEnabled(oldNotify);
}
}
}
public void removeEdgeModel(EObject diagramModel, EObject edgeModel) {
if(!(diagramModel instanceof org.eclipse.uml2.uml.Activity)) {
return;
}
DiagramAdapter diagramAdapter = BridgeHelper.getDiagramAdapter(diagramModel);
boolean oldNotify = false;
if(diagramAdapter != null) {
oldNotify = diagramAdapter.isNotificationEnabled();
diagramAdapter.setNotificationEnabled(false);
}
try {
((org.eclipse.uml2.uml.Activity) diagramModel).getEdges().remove(edgeModel);
}
finally {
if(diagramAdapter != null) {
diagramAdapter.setNotificationEnabled(oldNotify);
}
}
}
public void removeNodeModel(EObject diagramModel, EObject nodeModel) {
if(!(diagramModel instanceof org.eclipse.uml2.uml.Activity)) {
return;
}
DiagramAdapter diagramAdapter = BridgeHelper.getDiagramAdapter(diagramModel);
boolean oldNotify = false;
if(diagramAdapter != null) {
oldNotify = diagramAdapter.isNotificationEnabled();
diagramAdapter.setNotificationEnabled(false);
}
try {
((org.eclipse.uml2.uml.Activity) diagramModel).getNodes().remove(nodeModel);
}
finally {
if(diagramAdapter != null) {
diagramAdapter.setNotificationEnabled(oldNotify);
}
}
}
public Collection<?> getEdgeModels(EObject element) {
if(element instanceof org.eclipse.uml2.uml.Activity) {
return ((org.eclipse.uml2.uml.Activity) element).getEdges();
}
return Collections.EMPTY_LIST;
}
public Collection<?> getNodeModels(EObject element) {
if(element instanceof org.eclipse.uml2.uml.Activity) {
return ((org.eclipse.uml2.uml.Activity) element).getNodes();
}
return Collections.EMPTY_LIST;
}
};
private static final IDiagramAssociationHelper diagramAssociationHelper = new IDiagramAssociationHelper() {
public Node findNode(Diagram diagram, MethodElement e) {
return DiagramHelper.findNodeInModelDiagram(diagram, e);
}
public MethodElement getMethodElement(Node node, ResourceSet resourceSet) {
EObject element = node.getElement();
return element instanceof org.eclipse.epf.diagram.model.Node?
((org.eclipse.epf.diagram.model.Node) element).getLinkedElement() : null;
}
public void reassociate(Activity activity, Diagram copyOfBaseDiagram) {
// TODO Auto-generated method stub
}
public void addNodeModels(EObject diagramModel, Collection<?> nodeModels) {
if(!(diagramModel instanceof org.eclipse.epf.diagram.model.Diagram)) {
return;
}
org.eclipse.epf.diagram.model.Diagram diagram = (org.eclipse.epf.diagram.model.Diagram) diagramModel;
boolean oldNotify = ((NodeImpl)diagram).isNotificationEnabled();
try {
((NodeImpl)diagram).setNotificationEnabled(false);
diagram.getNodes().addAll((Collection<? extends org.eclipse.epf.diagram.model.Node>) nodeModels);
}
finally {
((NodeImpl)diagram).setNotificationEnabled(oldNotify);
}
}
public void addEdgeModels(EObject diagramModel, Collection<?> edgeModels) {
//
}
public void removeEdgeModel(EObject diagramModel, EObject edgeModel) {
}
public void removeNodeModel(EObject diagramModel, EObject nodeModel) {
if(!(diagramModel instanceof org.eclipse.epf.diagram.model.Diagram)) {
return;
}
org.eclipse.epf.diagram.model.Diagram diagram = (org.eclipse.epf.diagram.model.Diagram) diagramModel;
boolean oldNotify = ((NodeImpl)diagram).isNotificationEnabled();
try {
((NodeImpl)diagram).setNotificationEnabled(false);
diagram.getNodes().remove(nodeModel);
}
finally {
((NodeImpl)diagram).setNotificationEnabled(oldNotify);
}
}
public Collection<?> getEdgeModels(EObject element) {
return Collections.EMPTY_LIST;
}
public Collection<?> getNodeModels(EObject element) {
if(element instanceof org.eclipse.epf.diagram.model.Diagram) {
return ((org.eclipse.epf.diagram.model.Diagram) element).getNodes();
}
return Collections.EMPTY_LIST;
}
};
/**
* Checks if the given node is one of the specified nodes or their children.
*
* @param nodes
* @param node
*/
private static boolean contains(Collection<?> nodes, View node) {
if(nodes.contains(node)) {
return true;
}
for (Object child : nodes) {
if(child instanceof Node && contains(((Node) child).getChildren(), node)) {
return true;
}
}
return false;
}
private boolean doRefreshFromBase(Diagram diagram) {
Activity act = null;
EObject model = diagram.getElement();
if (model instanceof org.eclipse.uml2.uml.Activity) {
act = (Activity) BridgeHelper
.getMethodElement((EModelElement) model);
} else if (model instanceof org.eclipse.epf.diagram.model.Diagram) {
act = (Activity) ((org.eclipse.epf.diagram.model.Diagram) model)
.getLinkedElement();
}
if (act == null)
return false;
return doRefreshFromBase(diagram, act);
}
private boolean doRefreshFromBase(Diagram diagram, Activity act) {
EObject model = diagram.getElement();
Activity base = (Activity) act.getVariabilityBasedOnElement();
if (base == null
|| act.getVariabilityType() == VariabilityType.LOCAL_REPLACEMENT) {
return false;
}
int type = DiagramHelper.getDiagramType(diagram);
DiagramService diagramSvc = new DiagramService();
try {
Diagram baseDiagram = diagramSvc.getBaseDiagram(act, type);
if (baseDiagram == null)
return false;
Collection<Node> oldNodes = new HashSet<Node>();
Collection<Edge> oldEdges = new HashSet<Edge>();
Diagram baseCopy = DiagramHelper.copyDiagram(TransactionUtil
.getEditingDomain(diagram), baseDiagram);
IDiagramAssociationHelper helper = type == IDiagramManager.ACTIVITY_DIAGRAM ? ADAssociationHelper
: diagramAssociationHelper;
boolean notification = model.eDeliver();
try {
// model.eSetDeliver(false);
ResourceSet resourceSet = base.eResource().getResourceSet();
// Collect the base nodes that exist in extend diagram
for (Iterator<?> iter = baseDiagram.getChildren().iterator(); iter
.hasNext();) {
Node baseNode = (Node) iter.next();
MethodElement e = helper.getMethodElement(baseNode, resourceSet);
if (e != null) {
Node node = helper.findNode(diagram, e);
if (node != null) {
oldNodes.add(node);
}
}
}
// Collect old inherited UI nodes && nodes of
// contributor/replacer
List<?> children = diagram.getChildren();
for (Iterator<?> iter = children.iterator(); iter.hasNext();) {
Node node = (Node) iter.next();
if (BridgeHelper.isInherited(node)) {
oldNodes.add(node);
} else {
MethodElement e = helper.getMethodElement(node, resourceSet);
if (e instanceof Activity
&& ((Activity) e).getVariabilityBasedOnElement() != null) {
// node is of contributor or replacer
//
oldNodes.add(node);
}
}
}
Map<MethodElement, Edge> targetToCustomLinkMap = new HashMap<MethodElement, Edge>();
// Collect the edges thats exists in extend diagram
for (Iterator<?> iter = diagram.getEdges().iterator(); iter
.hasNext();) {
Edge edge = (Edge) iter.next();
if (contains(oldNodes, edge.getTarget())) {
if(contains(oldNodes, edge.getSource())) {
oldEdges.add(edge);
} else { // must be custom connection
MethodElement e = helper.getMethodElement((Node) edge.getTarget(), resourceSet);
targetToCustomLinkMap.put(e, edge);
}
}
}
// remove the old base nodes and edges that exists in the
// extend diagram.
for (Node node : oldNodes) {
diagram.removeChild(node);
helper.removeNodeModel(model, node.getElement());
}
for (Edge edge : oldEdges) {
diagram.removeEdge(edge);
helper.removeEdgeModel(model, edge.getElement());
edge.setSource(null);
edge.setTarget(null);
}
// replace associated base element with
// contributing/replacing
// element
//
helper.reassociate(act, baseCopy);
// Mark inherited
for (Object obj : baseCopy.getChildren()) {
View child = (View) obj;
BridgeHelper.markInherited(child);
if(child instanceof Node) {
MethodElement e = helper.getMethodElement((Node) child, resourceSet);
if(e != null) {
Edge edge = targetToCustomLinkMap.get(e);
if(edge != null) {
// update custom edge with new copy of target from base
edge.setTarget(child);
Object edgeModel = edge.getElement();
if(edgeModel instanceof ActivityEdge && child.getElement() instanceof ActivityNode) {
ActivityEdge actEdge = (ActivityEdge) edgeModel;
// disable notification for node adapter of
// the old target so associated work order
// will not be removed
ActivityNode oldTarget = actEdge.getTarget();
NodeAdapter nodeAdapter = BridgeHelper.getNodeAdapter(oldTarget);
boolean notify = false;
if(nodeAdapter != null) {
notify = nodeAdapter.isNotificationEnabled();
nodeAdapter.setNotificationEnabled(false);
}
try {
((ActivityEdge) edgeModel).setTarget((ActivityNode) child.getElement());
} finally {
if(nodeAdapter != null) {
nodeAdapter.setNotificationEnabled(notify);
}
}
}
}
}
}
}
for (Object obj : baseCopy.getEdges()) {
BridgeHelper.markInherited((View) obj);
}
// Add all new nodes and edges from base copy to extend diagram.
//
diagram.getPersistedChildren().addAll(
baseCopy.getChildren());
diagram.getPersistedEdges().addAll(
baseCopy.getEdges());
Collection<?> baseNodeModels = helper.getNodeModels(baseCopy.getElement());
if(baseNodeModels != null && !baseNodeModels.isEmpty()) {
helper.addNodeModels(model, baseNodeModels);
}
Collection<?> baseEdgeModels = helper.getEdgeModels(baseCopy
.getElement());
if (baseEdgeModels != null && !baseEdgeModels.isEmpty()) {
helper.addEdgeModels(model, baseEdgeModels);
}
// TODO: handle the missed links.
// ActivityDiagramAdapter adapter =
// (ActivityDiagramAdapter)BridgeHelper.getNodeAdapter(umlActivity);
// adapter.populateDiagram();
// if(targetPart instanceof AbstractDiagramEditor){
// DiagramEditorUtil.resetEditor((AbstractDiagramEditor)targetPart);
// }
} finally {
// reset the notification.
model.eSetDeliver(notification);
}
try {
if (targetPart instanceof AbstractDiagramEditor) {
DiagramEditorUtil
.resetEditor((AbstractDiagramEditor) targetPart);
}
// diagram.eResource().save(null);
} catch (Exception e) {
}
} finally {
diagramSvc.dispose();
}
return true;
}
public void initialize(){
if(targetPart instanceof AbstractDiagramEditor){
AbstractDiagramEditor editor = (AbstractDiagramEditor)targetPart;
DiagramEditPart part = editor.getDiagramEditPart();
}
}
}