Fix some bugs with copy/paste for Pools, Lanes and SubProcesses
diff --git a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/di/DIUtils.java b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/di/DIUtils.java
index b95ec8e..7db2963 100644
--- a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/di/DIUtils.java
+++ b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/di/DIUtils.java
@@ -13,7 +13,11 @@
 package org.eclipse.bpmn2.modeler.core.di;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.bpmn2.Association;
 import org.eclipse.bpmn2.BaseElement;
@@ -47,6 +51,7 @@
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
 import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer;
 import org.eclipse.emf.transaction.RecordingCommand;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
 import org.eclipse.graphiti.datatypes.IDimension;
@@ -573,14 +578,16 @@
 	 */
 	public static BPMNShape findBPMNShape(BaseElement baseElement) {
 		Definitions definitions = ModelUtil.getDefinitions(baseElement);
-		for (BPMNDiagram d : definitions.getDiagrams()) {
-			BPMNDiagram bpmnDiagram = (BPMNDiagram)d;
-			BaseElement bpmnElement = null;
-			for (DiagramElement de : bpmnDiagram.getPlane().getPlaneElement()) {
-				if (de instanceof BPMNShape) {
-					bpmnElement = ((BPMNShape)de).getBpmnElement();
-					if (bpmnElement == baseElement)
-						return (BPMNShape)de;
+		if (definitions!=null) {
+			for (BPMNDiagram d : definitions.getDiagrams()) {
+				BPMNDiagram bpmnDiagram = (BPMNDiagram)d;
+				BaseElement bpmnElement = null;
+				for (DiagramElement de : bpmnDiagram.getPlane().getPlaneElement()) {
+					if (de instanceof BPMNShape) {
+						bpmnElement = ((BPMNShape)de).getBpmnElement();
+						if (bpmnElement == baseElement)
+							return (BPMNShape)de;
+					}
 				}
 			}
 		}
@@ -648,7 +655,14 @@
 		BPMNDiagram bpmnDiagram = DIUtils.findBPMNDiagram(rootElement);
 		RootElement newRootElement = null;
 		if (bpmnDiagram==null) {
-			canDelete = true;
+			List<EObject> allObjects = new ArrayList<EObject>();
+			Map<EObject, Collection<EStructuralFeature.Setting>> usages;
+			TreeIterator<EObject> iter = rootElement.eContainer().eAllContents();
+			while (iter.hasNext())
+				allObjects.add(iter.next());
+				
+	        usages = UsageCrossReferencer.findAll(allObjects, rootElement);
+			canDelete = usages.isEmpty();
 		}
 		else {
 			// find a replacement for the BPMNDiagram target element
diff --git a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultConnectionRouter.java b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultConnectionRouter.java
index 50fac05..ebb0c69 100644
--- a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultConnectionRouter.java
+++ b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultConnectionRouter.java
@@ -18,13 +18,13 @@
 import java.util.List;
 
 import org.eclipse.bpmn2.BaseElement;
+import org.eclipse.bpmn2.FlowElementsContainer;
 import org.eclipse.bpmn2.Lane;
 import org.eclipse.bpmn2.di.BPMNShape;
 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.GraphicsUtil.LineSegment;
 import org.eclipse.emf.common.util.TreeIterator;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.graphiti.features.IFeatureProvider;
@@ -34,12 +34,9 @@
 import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
 import org.eclipse.graphiti.features.context.impl.DeleteContext;
 import org.eclipse.graphiti.features.impl.AbstractAddShapeFeature;
-import org.eclipse.graphiti.mm.MmFactory;
-import org.eclipse.graphiti.mm.Property;
 import org.eclipse.graphiti.mm.algorithms.Polyline;
 import org.eclipse.graphiti.mm.algorithms.styles.LineStyle;
 import org.eclipse.graphiti.mm.algorithms.styles.Point;
-import org.eclipse.graphiti.mm.impl.PropertyImpl;
 import org.eclipse.graphiti.mm.pictograms.Anchor;
 import org.eclipse.graphiti.mm.pictograms.Connection;
 import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator;
@@ -210,9 +207,18 @@
 		if (allShapes==null)
 			findAllShapes();
 		for (ContainerShape shape : allShapes) {
-			if (!FeatureSupport.isGroupShape(shape) && !FeatureSupport.isLabelShape(shape) && !FeatureSupport.isParticipant(shape))
+			if (!FeatureSupport.isGroupShape(shape) && !FeatureSupport.isLabelShape(shape) && !FeatureSupport.isParticipant(shape)) {
+				EObject bo = BusinessObjectUtil.getBusinessObjectForPictogramElement(shape);
+				if (bo instanceof FlowElementsContainer) {
+					// it's not a collision if the shape is a SubProcess and
+					// both source and target connection points lie inside the SubProcess
+					if (GraphicsUtil.contains(shape, p1) || GraphicsUtil.contains(shape, p2))
+						continue;
+				}
+				
 				if (GraphicsUtil.intersectsLine(shape, p1, p2))
 					collisions.add(shape);
+			}
 		}
 //		if (collisions.size()>0)
 //			GraphicsUtil.dump("Collisions with line ["+p1.getX()+", "+p1.getY()+"]"+" ["+p2.getX()+", "+p2.getY()+"]", collisions);
diff --git a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultPasteBPMNElementFeature.java b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultPasteBPMNElementFeature.java
index 5fd2d93..9ad91cf 100644
--- a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultPasteBPMNElementFeature.java
+++ b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/DefaultPasteBPMNElementFeature.java
@@ -21,7 +21,7 @@
 import org.eclipse.bpmn2.Association;
 import org.eclipse.bpmn2.BaseElement;
 import org.eclipse.bpmn2.BoundaryEvent;
-import org.eclipse.bpmn2.Bpmn2Package;
+import org.eclipse.bpmn2.Bpmn2Factory;
 import org.eclipse.bpmn2.Collaboration;
 import org.eclipse.bpmn2.ConversationLink;
 import org.eclipse.bpmn2.Definitions;
@@ -46,24 +46,25 @@
 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.GraphicsUtil.IShapeFilter;
 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;
 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.IAddFeature;
+import org.eclipse.graphiti.features.ICreateConnectionFeature;
 import org.eclipse.graphiti.features.IFeatureProvider;
 import org.eclipse.graphiti.features.IUpdateFeature;
+import org.eclipse.graphiti.features.context.ICreateConnectionContext;
 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.CreateConnectionContext;
 import org.eclipse.graphiti.features.context.impl.UpdateContext;
 import org.eclipse.graphiti.mm.algorithms.styles.Point;
 import org.eclipse.graphiti.mm.pictograms.Anchor;
@@ -164,6 +165,10 @@
 			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)
@@ -281,12 +286,42 @@
 		
 		return filteredObjects.toArray();
 	}
-	
+
+	public <T extends EObject> T copyEObject(T eObject) {
+		Copier copier = new Copier() {
+			@Override
+			protected EObject createCopy(EObject eObject) {
+				EClass eClass = getTarget(eObject.eClass());
+				if (eClass.getEPackage().getEFactoryInstance() == Bpmn2Factory.eINSTANCE) {
+					return Bpmn2ModelerFactory.create(resource, eClass);
+				}
+				return super.createCopy(eObject); 
+			}
+
+		};
+		EObject result = copier.copy(eObject);
+		copier.copyReferences();
+
+		@SuppressWarnings("unchecked")
+		T t = (T) result;
+		return t;
+	}
+
 	private BaseElement createNewObject(BaseElement oldObject, BaseElement targetContainerObject) {
 		Bpmn2ModelerFactory.setEnableModelExtensions(false);
-		BaseElement newObject = EcoreUtil.copy(oldObject);
+		BaseElement newObject = copyEObject(oldObject);
 		Bpmn2ModelerFactory.setEnableModelExtensions(true);
 
+		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.create(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
@@ -424,6 +459,14 @@
 		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()) {
@@ -500,6 +543,8 @@
 
 		// 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 
@@ -509,24 +554,29 @@
 					// 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) {
-					copyShape(oldChildShape, newShape, 0, 0);
+					childShapes.add(oldChildShape);
+				}
+				Connection oldChildConnection = findConnection(oldChildObject);
+				if (oldChildConnection != null) {
+					childConnections.add(oldChildConnection);
 				}
 			}
 			
-			iter = oldObject.eAllContents();
-			while (iter.hasNext()) {
-				// do the same for connections 
-				EObject oldChildObject = iter.next();
-				// if the old child has a Graphiti Connection, duplicate it.
-				Connection oldChildConnection = findConnection(oldChildObject);
-				if (oldChildConnection != null) {
-					// the old BPMN2 object is a Connection, copy it
-					copyConnection(oldChildConnection, newShape, x, y);
-				}
+			for (ContainerShape oldChildShape : childShapes) {
+				copyShape(oldChildShape, newShape, 0, 0);
+			}
+			
+			for (Connection oldChildConnection : childConnections) {
+				copyConnection(oldChildConnection, newShape, x, y);
 			}
 		}
 		else if (oldObject instanceof Lane) {
@@ -660,7 +710,7 @@
 			}
 		}
 		
-		// also copy the BPMNShape properties
+		// also copy the BPMNEdge properties
 		if (oldObject instanceof BaseElement) {
 			BPMNEdge oldBpmnEdge = DIUtils.findBPMNEdge((BaseElement)oldObject);
 			if (oldBpmnEdge!=null) {
@@ -683,7 +733,7 @@
 			public boolean matches(Shape shape) {
 				if (shape instanceof ContainerShape) {
 					BaseElement be = getContainerObject((ContainerShape) shape);
-					return be instanceof FlowElementsContainer;
+					return be instanceof FlowElementsContainer || be instanceof Participant;
 				}
 				return false;
 			}
@@ -699,9 +749,11 @@
 			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)
+		if (bo instanceof FlowElementsContainer || bo instanceof Lane || bo instanceof Collaboration)
 			return (BaseElement) bo;
 		return null;
 	}
diff --git a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/label/UpdateLabelFeature.java b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/label/UpdateLabelFeature.java
index 6675631..7c3c5e1 100644
--- a/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/label/UpdateLabelFeature.java
+++ b/plugins/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/features/label/UpdateLabelFeature.java
@@ -231,10 +231,12 @@
 				BPMNLabel bpmnLabel = null;
 				if (ownerPE instanceof Connection) {
 					BPMNEdge bpmnEdge = DIUtils.findBPMNEdge(element);
-					bpmnLabel = bpmnEdge.getLabel();
+					if (bpmnEdge!=null)
+						bpmnLabel = bpmnEdge.getLabel();
 				} else {
 					BPMNShape bpmnShape = DIUtils.findBPMNShape(element);
-					bpmnLabel = bpmnShape.getLabel();
+					if (bpmnShape!=null)
+						bpmnLabel = bpmnShape.getLabel();
 				}
 				Bounds bounds = bpmnLabel == null ? null : bpmnLabel.getBounds();
 
diff --git a/plugins/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/editor/ConnectionLayerClippingStrategy.java b/plugins/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/editor/ConnectionLayerClippingStrategy.java
index ae3f910..0700cdd 100644
--- a/plugins/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/editor/ConnectionLayerClippingStrategy.java
+++ b/plugins/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/editor/ConnectionLayerClippingStrategy.java
@@ -27,6 +27,7 @@
 import org.eclipse.gef.GraphicalViewer;
 import org.eclipse.gef.LayerConstants;
 import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
+import org.eclipse.graphiti.datatypes.ILocation;
 import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
 import org.eclipse.graphiti.mm.pictograms.AnchorContainer;
 import org.eclipse.graphiti.mm.pictograms.Connection;
@@ -143,7 +144,8 @@
 	}
 	
 	private Rectangle[] getClip(ContainerShape pe) {
+		ILocation loc = Graphiti.getPeService().getLocationRelativeToDiagram(pe);
 		GraphicsAlgorithm ga = pe.getGraphicsAlgorithm();
-		return new Rectangle[] { new Rectangle(ga.getX(), ga.getY(), ga.getWidth(), ga.getHeight()) };
+		return new Rectangle[] { new Rectangle(loc.getX(), loc.getY(), ga.getWidth(), ga.getHeight()) };
 	}
 }