blob: cc4f6331561be65c77dbb4390d7dac45a028671a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012, 2013 Red Hat, Inc.
* All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.bpmn2.modeler.core.features;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
import org.eclipse.bpmn2.Activity;
import org.eclipse.bpmn2.Association;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.BoundaryEvent;
import org.eclipse.bpmn2.Bpmn2Factory;
import org.eclipse.bpmn2.Collaboration;
import org.eclipse.bpmn2.ConversationLink;
import org.eclipse.bpmn2.Definitions;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.FlowElementsContainer;
import org.eclipse.bpmn2.FlowNode;
import org.eclipse.bpmn2.InteractionNode;
import org.eclipse.bpmn2.Lane;
import org.eclipse.bpmn2.LaneSet;
import org.eclipse.bpmn2.MessageFlow;
import org.eclipse.bpmn2.Participant;
import org.eclipse.bpmn2.Process;
import org.eclipse.bpmn2.SequenceFlow;
import org.eclipse.bpmn2.di.BPMNDiagram;
import org.eclipse.bpmn2.di.BPMNEdge;
import org.eclipse.bpmn2.di.BPMNShape;
import org.eclipse.bpmn2.modeler.core.adapters.ExtendedPropertiesAdapter;
import org.eclipse.bpmn2.modeler.core.adapters.FeatureDescriptor;
import org.eclipse.bpmn2.modeler.core.di.DIUtils;
import org.eclipse.bpmn2.modeler.core.model.Bpmn2ModelerFactory;
import org.eclipse.bpmn2.modeler.core.utils.AnchorUtil;
import org.eclipse.bpmn2.modeler.core.utils.BusinessObjectUtil;
import org.eclipse.bpmn2.modeler.core.utils.FeatureSupport;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.graphiti.datatypes.IDimension;
import org.eclipse.graphiti.datatypes.ILocation;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.IUpdateFeature;
import org.eclipse.graphiti.features.context.IPasteContext;
import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
import org.eclipse.graphiti.features.context.impl.AddContext;
import org.eclipse.graphiti.features.context.impl.AreaContext;
import org.eclipse.graphiti.features.context.impl.UpdateContext;
import org.eclipse.graphiti.mm.algorithms.styles.Point;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.FreeFormConnection;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.graphiti.ui.features.AbstractPasteFeature;
/**
* Default Graphiti {@code PasteFeature} class for Shapes.
* <p>
*/
public class DefaultPasteBPMNElementFeature extends AbstractPasteFeature {
/** The EMF Resource. */
protected Resource resource;
/** The BPMN2 Definitions object - the root element of the document. */
protected Definitions definitions;
/**
* Maps the ID strings of the original BPMN2 elements to their
* corresponding newly constructed copies.
*/
protected Hashtable<String, String> idMap;
/** The shape map. */
protected HashMap<ContainerShape, ContainerShape> shapeMap;
/** The connection map. */
protected HashMap<Connection, Connection> connectionMap;
/** The x reference. */
protected int xReference;
/** The y reference. */
protected int yReference;
/** The diagram. */
protected Diagram diagram;
/**
* Instantiates a new default {@code PasteFeature).
*
* @param fp the Feature Provider
*/
public DefaultPasteBPMNElementFeature(IFeatureProvider fp) {
super(fp);
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IPasteFeature#canPaste(org.eclipse.graphiti.features.context.IPasteContext)
*/
@Override
public boolean canPaste(IPasteContext context) {
// target must be a FlowElementsContainer (Process, etc.)
ContainerShape targetContainerShape = getTargetContainerShape(context);
if (targetContainerShape==null)
return false;
BaseElement targetContainerObject = getContainerObject(targetContainerShape);
if (targetContainerObject==null)
return false;
Object[] pasteObjects;
if (context.getProperty(GraphitiConstants.COPY_FROM_CONTEXT) != null) {
// Get objects to paste from the context. This can be used to test if
// objects can be pasted before they have been copied to the clipboard.
pasteObjects = context.getPictogramElements();
}
else {
// can paste, if all objects on the clipboard are PictogramElements
pasteObjects = getFromClipboard();
}
if (pasteObjects == null || pasteObjects.length == 0) {
return false;
}
int count = 0;
for (Object object : pasteObjects) {
if (!(object instanceof PictogramElement)) {
continue;
}
PictogramElement pe = (PictogramElement) object;
BaseElement be = BusinessObjectUtil.getFirstBaseElement(pe);
if (!(be instanceof FlowElement) && !(be instanceof Lane) && !(be instanceof Participant)) {
continue;
}
// can't paste Boundary Events directly - these are "carried along"
// by the Activity to which they are attached.
if (be instanceof BoundaryEvent) {
continue;
}
// can't paste Label shapes
if (pe instanceof Shape && FeatureSupport.isLabelShape((Shape)pe)) {
continue;
}
// Participants can only be pasted into into a Collaboration
if (be instanceof Participant && !(targetContainerObject instanceof Collaboration)) {
continue;
}
++count;
}
if (count==0)
return false;
return true;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IPasteFeature#paste(org.eclipse.graphiti.features.context.IPasteContext)
*/
@Override
public void paste(IPasteContext context) {
ContainerShape targetContainerShape = getTargetContainerShape(context);
BaseElement targetContainerObject = getContainerObject(targetContainerShape);
// save the Diagram and Resource needed for constructing the new objects
diagram = getFeatureProvider().getDiagramTypeProvider().getDiagram();
resource = targetContainerObject.eResource();
definitions = ModelUtil.getDefinitions(resource);
idMap = new Hashtable<String, String>();
shapeMap = new HashMap<ContainerShape, ContainerShape>();
connectionMap = new HashMap<Connection, Connection>();
xReference = 0;
yReference = 0;
int xMin = Integer.MAX_VALUE;
int yMin = Integer.MAX_VALUE;
Object[] fromClipboard = getFromClipboard();
for (Object object : fromClipboard) {
if (object instanceof ContainerShape) {
ILocation loc = Graphiti.getLayoutService().getLocationRelativeToDiagram((ContainerShape) object);
if (loc.getX() < xMin) {
xMin = loc.getX();
}
if (loc.getY() < yMin) {
yMin = loc.getY();
}
}
}
if (xMin!=Integer.MAX_VALUE) {
xReference = xMin;
yReference = yMin;
}
int x = context.getX();
int y = context.getY();
if (!(targetContainerShape instanceof Diagram)) {
ILocation loc = Graphiti.getLayoutService().getLocationRelativeToDiagram(targetContainerShape);
x -= loc.getX();
y -= loc.getY();
}
// First create all shapes. This creates a lookup map of old to new
// ContainerShape objects.
for (Object object : fromClipboard) {
if (object instanceof ContainerShape) {
copyShape((ContainerShape) object, targetContainerShape, x, y);
}
}
// Handle connections now that we know all shapes have been created
x = context.getX(); // Connection bendpoint coordinates are always
// relative to diagram
y = context.getY();
for (Object object : fromClipboard) {
if (object instanceof Connection) {
copyConnection((Connection) object, targetContainerShape, x, y);
}
}
// handle any connections that were not created because of missing source/target
for (Entry<Connection, Connection> entry : connectionMap.entrySet()) {
if (entry.getValue()==null) {
copyConnection(entry.getKey(), targetContainerShape, x, y);
}
}
PictogramElement newPes[] = new PictogramElement[shapeMap.size()];
int i = 0;
for (Entry<ContainerShape, ContainerShape> entry : shapeMap.entrySet()) {
newPes[i++] = entry.getValue();
}
getDiagramEditor().setPictogramElementsForSelection(newPes);
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.ui.features.AbstractPasteFeature#getFromClipboard()
*/
protected Object[] getFromClipboard() {
List<Object> allObjects = new ArrayList<Object>();
Object[] objects = super.getFromClipboard();
for (Object object : objects) {
if (object instanceof EObject && ((EObject)object).eContainer()!=null)
allObjects.add(object);
}
List<Object> filteredObjects = new ArrayList<Object>();
for (Object object : allObjects) {
if (object instanceof EObject && ((EObject)object).eContainer()!=null) {
if (object instanceof ContainerShape) {
filteredObjects.add(object);
}
else if (object instanceof Connection) {
Connection c = (Connection)object;
if (c.getStart()!=null && c.getEnd()!=null) {
if (allObjects.contains(c.getStart().getParent()) &&
allObjects.contains(c.getEnd().getParent())) {
filteredObjects.add(object);
}
}
}
}
}
return filteredObjects.toArray();
}
public <T extends EObject> T copyEObject(T eObject) {
Copier copier = new Copier() {
private static final long serialVersionUID = 1L;
@Override
protected EObject createCopy(EObject eObject) {
EClass eClass = getTarget(eObject.eClass());
if (eClass.getEPackage().getEFactoryInstance() == Bpmn2Factory.eINSTANCE) {
return Bpmn2ModelerFactory.createObject(resource, eClass);
}
return super.createCopy(eObject);
}
};
EObject result = copier.copy(eObject);
copier.copyReferences();
@SuppressWarnings("unchecked")
T t = (T) result;
// don't set a name on the new object if old object didn't have one.
EStructuralFeature f = t.eClass().getEStructuralFeature("name"); //$NON-NLS-1$
if (f!=null) {
String name = (String)eObject.eGet(f);
if (name==null || name.isEmpty())
t.eSet(f, null);
}
// add metadata to the ExtendedPropertiesAdapter for extension features
ExtendedPropertiesAdapter<T> oldAdapter = ExtendedPropertiesAdapter.adapt(eObject);
ExtendedPropertiesAdapter<T> newAdapter = ExtendedPropertiesAdapter.adapt(result);
for (EStructuralFeature oldFeature : oldAdapter.getExtensionFeatures()) {
FeatureDescriptor fd = newAdapter.getFeatureDescriptor(oldFeature);
fd.setProperty(ExtendedPropertiesAdapter.IS_EXTENSION_FEATURE, Boolean.TRUE);
}
return t;
}
private BaseElement createNewObject(BaseElement oldObject, BaseElement targetContainerObject) {
BaseElement newObject = null;
try {
Bpmn2ModelerFactory.lock();
Bpmn2ModelerFactory.setEnableModelExtensions(false);
newObject = copyEObject(oldObject);
}
finally {
Bpmn2ModelerFactory.setEnableModelExtensions(true);
Bpmn2ModelerFactory.unlock();
}
if (targetContainerObject instanceof Participant) {
// need to create a Process for target container if it doesn't have one yet
Participant participant = (Participant) targetContainerObject;
if (participant.getProcessRef()==null) {
Process process = Bpmn2ModelerFactory.createObject(resource, Process.class);
participant.setProcessRef(process);
}
targetContainerObject = participant.getProcessRef();
}
// get rid of some of the objects created by EcoreUtil.copy() as these will be
// constructed here because we need to create the Graphiti shapes and DI elements
// along with these
if (newObject instanceof FlowElementsContainer) {
// we will create our own FlowElements, thank you!
((FlowElementsContainer)newObject).getFlowElements().clear();
}
if (newObject instanceof Lane) {
// we will construct these ourselves
((Lane) newObject).getFlowNodeRefs().clear();
((Lane) newObject).setChildLaneSet(null);
if (targetContainerObject instanceof FlowElementsContainer) {
FlowElementsContainer fc = (FlowElementsContainer)targetContainerObject;
if (fc.getLaneSets().size()!=0) {
fc.getLaneSets().get(0).getLanes().add((Lane)newObject);
}
else {
LaneSet ls = Bpmn2ModelerFactory.createObject(resource, LaneSet.class);
fc.getLaneSets().add(ls);
ls.getLanes().add((Lane)newObject);
}
}
else if (targetContainerObject instanceof Lane) {
Lane ln = (Lane)targetContainerObject;
if (ln.getChildLaneSet()==null) {
LaneSet ls = Bpmn2ModelerFactory.createObject(resource, LaneSet.class);
ln.setChildLaneSet(ls);
}
ln.getChildLaneSet().getLanes().add((Lane)newObject);
}
}
else if (newObject instanceof FlowElement) {
if (targetContainerObject instanceof Lane) {
Lane ln = (Lane)targetContainerObject;
targetContainerObject = getFlowElementsContainer(ln);
// newObject could be either a Shape (FlowNode) or a Connection;
// only add FlowNodes to the Lane's FlowNodeRefs list.
if (newObject instanceof FlowNode)
ln.getFlowNodeRefs().add((FlowNode)newObject);
}
if (targetContainerObject instanceof FlowElementsContainer) {
((FlowElementsContainer)targetContainerObject).getFlowElements().add((FlowElement) newObject);
}
}
else if (newObject instanceof Participant) {
Participant participant = (Participant)newObject;
if (((Participant) newObject).getProcessRef()!=null) {
// need to create a new Process for this thing
Process process = Bpmn2ModelerFactory.createObject(resource, Process.class);
participant.setProcessRef(process);
}
if (targetContainerObject instanceof Collaboration) {
Collaboration collab = (Collaboration)targetContainerObject;
collab.getParticipants().add((Participant)newObject);
}
}
// Ensure IDs are unique
setId(newObject);
TreeIterator<EObject> iter = newObject.eAllContents();
while (iter.hasNext()) {
EObject newChild = iter.next();
setId(newChild);
}
for (EReference ref : newObject.eClass().getEAllReferences()) {
if (!ref.isContainment()) {
Object oldValue = oldObject.eGet(ref);
// TODO: do we need this?
// this mess also duplicates "incoming" and "outgoing" (for SequenceFlows)
// which are already being handled in copyConnection()...
// if (oldValue instanceof EObjectEList) {
// EObjectEList oldList = (EObjectEList)oldObject.eGet(ref);
// EObjectEList newList = (EObjectEList)newObject.eGet(ref);
// for (Object oldRefObject : oldList) {
// if (oldRefObject instanceof EObject) {
// String oldId = getId((EObject)oldRefObject);
// if (oldId!=null) {
// String newId = idMap.get(oldId);
// EObject newRefObject = findObjectById(newId);
// newList.add(newRefObject);
// }
// }
// }
// }
// else
if (oldValue instanceof EObject){
EObject oldRefObject = (EObject)oldValue;
String oldId = getId(oldRefObject);
if (oldId!=null) {
String newId = idMap.get(oldId);
if (newId!=null) {
EObject newRefObject = findObjectById(newId);
newObject.eSet(ref, newRefObject);
}
else if (newObject.eGet(ref) != null){
EObject newRefObject = (EObject) newObject.eGet(ref);
newId = getId(newRefObject);
if (newId!=null)
idMap.put(oldId, newId);
}
}
}
}
}
return newObject;
}
private String getId(EObject newObject) {
EStructuralFeature feature = newObject.eClass().getEStructuralFeature("id"); //$NON-NLS-1$
if (feature != null) {
return (String) newObject.eGet(feature);
}
return null;
}
private String setId(EObject newObject) {
String newId = null;
String oldId = null;
EStructuralFeature feature = newObject.eClass().getEStructuralFeature("id"); //$NON-NLS-1$
if (feature != null) {
oldId = (String) newObject.eGet(feature);
if (idMap.contains(oldId)) {
newId = idMap.get(oldId);
newObject.eSet(feature, newId);
}
else {
newObject.eUnset(feature);
newId = ModelUtil.setID(newObject);
idMap.put(oldId, newId);
}
}
return oldId;
}
private boolean wasCopied(EObject object) {
String id = getId(object);
if (id!=null) {
return idMap.containsValue(id);
}
return false;
}
private EObject findObjectById(String id) {
TreeIterator<EObject> iter = definitions.eAllContents();
while (iter.hasNext()) {
EObject o = iter.next();
EStructuralFeature feature = o.eClass().getEStructuralFeature("id"); //$NON-NLS-1$
if (feature != null) {
String thisId = (String) o.eGet(feature);
if (thisId != null && !thisId.isEmpty() && thisId.equals(id))
return o;
}
}
return null;
}
private ContainerShape findShape(EObject object) {
List<PictogramElement> pes = Graphiti.getLinkService().getPictogramElements(diagram, object);
for (PictogramElement pe : pes) {
if (pe instanceof ContainerShape)
return (ContainerShape) pe;
}
return null;
}
private Connection findConnection(EObject object) {
List<PictogramElement> pes = Graphiti.getLinkService().getPictogramElements(diagram, object);
for (PictogramElement pe : pes) {
if (pe instanceof Connection)
return (Connection) pe;
}
return null;
}
private BaseElement copyShape(ContainerShape oldShape, ContainerShape targetContainerShape, int x, int y) {
if (shapeMap.get(oldShape)!=null)
return null;
BaseElement targetContainerObject = getContainerObject(targetContainerShape);
BaseElement oldObject = BusinessObjectUtil.getFirstBaseElement(oldShape);
BaseElement newObject = createNewObject(oldObject, targetContainerObject);
AddContext ac = new AddContext(new AreaContext(), newObject);
ILocation loc = Graphiti.getLayoutService().getLocationRelativeToDiagram(oldShape);
IDimension size = GraphicsUtil.calculateSize(oldShape);
// The default Add BPMN Shape feature will position the new shape so its
// center is at the target location; for copy/paste we want to use the
// top-left corner instead so that copied connection bendpoints (if any)
// line up properly.
int deltaX = 0;
int deltaY = 0;
if (oldObject instanceof FlowNode) {
deltaX = loc.getX() - xReference + size.getWidth() / 2;
deltaY = loc.getY() - yReference + size.getHeight() / 2;
}
ac.setLocation(x + deltaX, y + deltaY);
ac.setSize(size.getWidth(), size.getHeight());
ac.setTargetContainer(targetContainerShape);
BPMNShape oldBpmnShape = null;
if (oldObject instanceof BaseElement) {
BPMNDiagram bpmnDiagram = DIUtils.findBPMNDiagram(oldShape);
oldBpmnShape = DIUtils.findBPMNShape(bpmnDiagram, (BaseElement)oldObject);
ac.putProperty(GraphitiConstants.COPIED_BPMN_DI_ELEMENT, oldBpmnShape);
}
ac.putProperty(GraphitiConstants.COPIED_BPMN_OBJECT, oldObject);
ContainerShape newShape = (ContainerShape) getFeatureProvider().addIfPossible(ac);
shapeMap.put(oldShape, newShape);
if (oldObject instanceof Participant) {
// copy the contained Process elements
oldObject = ((Participant)oldObject).getProcessRef();
}
// create shapes and connections for children if this is a FlowElementsContainer
if (oldObject instanceof FlowElementsContainer) {
List<ContainerShape> childShapes = new ArrayList<ContainerShape>();
List<Connection> childConnections = new ArrayList<Connection>();
TreeIterator<EObject> iter = oldObject.eAllContents();
while (iter.hasNext()) {
// look up the old child object that corresponds to the new child object
EObject oldChildObject = iter.next();
if (oldChildObject instanceof BoundaryEvent) {
// Defer Boundary Event creation until we're sure that the
// new attachedToRef task is actually created.
continue;
}
if (wasCopied(oldChildObject)) {
// stop infinite recursion: this would happen if a FlowElementsContainer
//was copied into itself.
continue;
}
// if the old child has a Graphiti ContainerShape, duplicate it.
ContainerShape oldChildShape = findShape(oldChildObject);
if (oldChildShape != null) {
childShapes.add(oldChildShape);
}
Connection oldChildConnection = findConnection(oldChildObject);
if (oldChildConnection != null) {
childConnections.add(oldChildConnection);
}
}
for (ContainerShape oldChildShape : childShapes) {
copyShape(oldChildShape, newShape, 0, 0);
}
for (Connection oldChildConnection : childConnections) {
copyConnection(oldChildConnection, newShape, x, y);
}
}
else if (oldObject instanceof Lane) {
List<PictogramElement> shapes = new ArrayList<PictogramElement>();
Lane oldLane = (Lane)oldObject;
if (oldLane.getChildLaneSet()!=null) {
for (Lane oldChildLaneObject : oldLane.getChildLaneSet().getLanes()) {
ContainerShape oldChildLaneShape = findShape(oldChildLaneObject);
if (oldChildLaneShape != null) {
copyShape(oldChildLaneShape, newShape, 0, 0);
}
}
}
for (FlowNode oldChildObject : oldLane.getFlowNodeRefs()) {
ContainerShape oldChildShape = findShape(oldChildObject);
if (oldChildShape != null) {
copyShape(oldChildShape, newShape, 0, 0);
shapes.add(oldChildShape);
}
}
List<Connection> connections = DefaultCopyBPMNElementFeature.findAllConnections(shapes);
for (Connection oldChildConnection : connections) {
copyConnection(oldChildConnection, newShape, x, y);
}
}
// also copy the BPMNShape properties
if (oldBpmnShape!=null) {
BPMNShape newBpmnShape = DIUtils.findBPMNShape((BaseElement)newObject);
newBpmnShape.setIsExpanded(oldBpmnShape.isIsExpanded());
newBpmnShape.setIsHorizontal(oldBpmnShape.isIsHorizontal());
newBpmnShape.setIsMarkerVisible(oldBpmnShape.isIsMarkerVisible());
newBpmnShape.setIsMessageVisible(oldBpmnShape.isIsMessageVisible());
newBpmnShape.setParticipantBandKind(oldBpmnShape.getParticipantBandKind());
}
UpdateContext uc = new UpdateContext(newShape);
IUpdateFeature uf = getFeatureProvider().getUpdateFeature(uc);
// force an update to cause the newly created ContainerShape to be rendered properly
uc.putProperty(GraphitiConstants.FORCE_UPDATE_ALL, Boolean.TRUE);
uf.update(uc);
if (newObject instanceof Activity) {
// copy the Activity's Boundary Events if it has any
TreeIterator<EObject> i = definitions.eAllContents();
while (i.hasNext()) {
EObject o = i.next();
if (o instanceof BoundaryEvent) {
BoundaryEvent oldBeObject = (BoundaryEvent)o;
if (oldBeObject.getAttachedToRef() == oldObject) {
// here's one...
ContainerShape oldBeShape = findShape(oldBeObject);
copyShape(oldBeShape, targetContainerShape, x, y);
}
}
}
}
return newObject;
}
private BaseElement copyConnection(Connection oldConnection, ContainerShape targetContainerShape, int x, int y) {
if (connectionMap.get(oldConnection)!=null)
return null;
BaseElement targetContainerObject = getContainerObject(targetContainerShape);
BaseElement oldObject = BusinessObjectUtil.getFirstBaseElement(oldConnection);
BaseElement newObject = createNewObject(oldObject, targetContainerObject);
Anchor oldStart = oldConnection.getStart();
Anchor oldEnd = oldConnection.getEnd();
ContainerShape newSource = shapeMap.get(oldStart.getParent());
ContainerShape newTarget = shapeMap.get(oldEnd.getParent());
if (newSource==null || newTarget==null) {
// source or target does not exist yet - handle this connection later
connectionMap.put(oldConnection, null);
return null;
}
Anchor newStart;
Anchor newEnd;
ILocation loc = Graphiti.getLayoutService().getLocationRelativeToDiagram(oldStart);
newStart = AnchorUtil.createAnchor(newSource, loc.getX(), loc.getY());
loc = Graphiti.getLayoutService().getLocationRelativeToDiagram(oldEnd);
newEnd = AnchorUtil.createAnchor(newTarget, loc.getX(), loc.getY());
BaseElement newSourceObject = BusinessObjectUtil.getFirstBaseElement(newSource);
BaseElement newTargetObject = BusinessObjectUtil.getFirstBaseElement(newTarget);
if (newObject instanceof SequenceFlow) {
((SequenceFlow) newObject).setSourceRef((FlowNode) newSourceObject);
((SequenceFlow) newObject).setTargetRef((FlowNode) newTargetObject);
}
else if (newObject instanceof Association) {
((Association) newObject).setSourceRef((FlowNode) newSourceObject);
((Association) newObject).setTargetRef((FlowNode) newTargetObject);
}
else if (newObject instanceof MessageFlow) {
((MessageFlow) newObject).setSourceRef((InteractionNode) newSourceObject);
((MessageFlow) newObject).setTargetRef((InteractionNode) newTargetObject);
}
else if (newObject instanceof ConversationLink) {
((ConversationLink) newObject).setSourceRef((InteractionNode) newSourceObject);
((ConversationLink) newObject).setTargetRef((InteractionNode) newTargetObject);
}
AddConnectionContext acc = new AddConnectionContext(newStart, newEnd);
acc.setNewObject(newObject);
Connection newConnection = (Connection) getFeatureProvider().addIfPossible(acc);
connectionMap.put(oldConnection, newConnection);
if (oldConnection instanceof FreeFormConnection && newConnection instanceof FreeFormConnection) {
for (Point p : ((FreeFormConnection) oldConnection).getBendpoints()) {
int deltaX = p.getX() - xReference;
int deltaY = p.getY() - yReference;
Point newPoint = GraphicsUtil.createPoint(x + deltaX, y + deltaY);
((FreeFormConnection) newConnection).getBendpoints().add(newPoint);
}
}
// also copy the BPMNEdge properties
if (oldObject instanceof BaseElement) {
BPMNDiagram bpmnDiagram = DIUtils.findBPMNDiagram(oldConnection);
BPMNEdge oldBpmnEdge = DIUtils.findBPMNEdge(bpmnDiagram, (BaseElement)oldObject);
if (oldBpmnEdge!=null) {
bpmnDiagram = DIUtils.findBPMNDiagram(newConnection);
BPMNEdge newBpmnEdge = DIUtils.findBPMNEdge(bpmnDiagram, (BaseElement)newObject);
newBpmnEdge.setMessageVisibleKind(oldBpmnEdge.getMessageVisibleKind());
}
}
FeatureSupport.updateConnection(getFeatureProvider(), newConnection);
return newObject;
}
private ContainerShape getTargetContainerShape(IPasteContext context) {
Diagram diagram = getFeatureProvider().getDiagramTypeProvider().getDiagram();
Point p = GraphicsUtil.createPoint(context.getX(), context.getY());
Shape s = GraphicsUtil.findShapeAt(diagram, p, new GraphicsUtil.IShapeFilter() {
@Override
public boolean matches(Shape shape) {
if (shape instanceof ContainerShape) {
BaseElement be = getContainerObject((ContainerShape) shape);
return be instanceof FlowElementsContainer || be instanceof Participant;
}
return false;
}
});
if (s!=null)
return (ContainerShape) s;
return diagram;
}
private BaseElement getContainerObject(ContainerShape targetContainerShape) {
EObject bo = BusinessObjectUtil.getBusinessObjectForPictogramElement(targetContainerShape);
if (bo instanceof BPMNDiagram) {
bo = ((BPMNDiagram) bo).getPlane().getBpmnElement();
}
if (bo instanceof Participant) {
if (!FeatureSupport.isChoreographyParticipantBand(targetContainerShape))
return (Participant) bo;
bo = ((Participant) bo).getProcessRef();
}
if (bo instanceof FlowElementsContainer || bo instanceof Lane || bo instanceof Collaboration)
return (BaseElement) bo;
return null;
}
private FlowElementsContainer getFlowElementsContainer(Lane lane) {
EObject container = lane.eContainer();
while (!(container instanceof FlowElementsContainer) && container!=null)
container = container.eContainer();
return (FlowElementsContainer)container;
}
protected DiagramEditor getDiagramEditor() {
return (DiagramEditor)getFeatureProvider().getDiagramTypeProvider().getDiagramBehavior().getDiagramContainer();
}
}