/******************************************************************************* | |
* <copyright> | |
* | |
* Copyright (c) 2013, 2013 SAP AG. | |
* 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: | |
* SAP AG - initial API, implementation and documentation | |
* | |
* </copyright> | |
* | |
*******************************************************************************/ | |
package org.eclipse.fmc.blockdiagram.editor.features; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map; | |
import org.eclipse.draw2d.geometry.Point; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.util.EcoreUtil; | |
import org.eclipse.fmc.blockdiagram.editor.BlockDiagramEditor; | |
import org.eclipse.fmc.blockdiagram.editor.clipboard.PasteFromClipboard; | |
import org.eclipse.fmc.blockdiagram.editor.model.FMCType; | |
import org.eclipse.fmc.blockdiagram.editor.util.FMCUtil; | |
import org.eclipse.graphiti.datatypes.ILocation; | |
import org.eclipse.graphiti.features.IFeatureProvider; | |
import org.eclipse.graphiti.features.context.IAddContext; | |
import org.eclipse.graphiti.features.context.IAreaContext; | |
import org.eclipse.graphiti.features.context.IPasteContext; | |
import org.eclipse.graphiti.features.context.impl.AddContext; | |
import org.eclipse.graphiti.internal.datatypes.impl.LocationImpl; | |
import org.eclipse.graphiti.mm.pictograms.Connection; | |
import org.eclipse.graphiti.mm.pictograms.ContainerShape; | |
import org.eclipse.graphiti.mm.pictograms.PictogramElement; | |
import org.eclipse.graphiti.mm.pictograms.Shape; | |
import org.eclipse.graphiti.ui.editor.DiagramEditor; | |
import org.eclipse.graphiti.ui.features.AbstractPasteFeature; | |
/** | |
* Paste feature which supports pasting of shapes and images from the clipboard. | |
* | |
* @author Benjamin Schmeling | |
* | |
*/ | |
@SuppressWarnings("restriction") | |
public class ShapePasteFeature extends AbstractPasteFeature { | |
/** | |
* Main constructor. | |
* | |
* @param featureProvider The feature provider. | |
*/ | |
public ShapePasteFeature(IFeatureProvider featureProvider) { | |
super(featureProvider); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see | |
* org.eclipse.graphiti.features.IPasteFeature#paste(org.eclipse.graphiti | |
* .features.context.IPasteContext) | |
*/ | |
@Override | |
public void paste(IPasteContext context) { | |
DiagramEditor activeEditor = (DiagramEditor) FMCUtil | |
.getActiveEditor(); | |
Point p = activeEditor.getDiagramBehavior().calculateRealMouseLocation(activeEditor.getDiagramBehavior() | |
.getMouseLocation()); | |
Object[] objects = getFromClipboard(); | |
if (objects != null && objects.length > 0) { | |
pastePictogramElements(context, p, objects); | |
} else { | |
pasteImage(context); | |
} | |
} | |
/** | |
* Pastes the image into the diagram. | |
* | |
* @param context The paste context. | |
*/ | |
private void pasteImage(IPasteContext context) { | |
String imageId = PasteFromClipboard | |
.pasteImagesFromClipboard((BlockDiagramEditor) getDiagramBehavior().getDiagramContainer()); | |
// we already verified, that we paste directly in the diagram | |
if (imageId != null) { | |
AddContext ac = new AddContext(); | |
ac.setLocation((Integer) context.getProperty("mouseX"), | |
(Integer) context.getProperty("mouseY")); | |
ac.setTargetContainer(getDiagram()); | |
ac.putProperty("imageid", imageId); | |
ac.setNewObject(getImageModelObject()); | |
addGraphicalRepresentation(ac, getImageModelObject()); | |
} | |
} | |
/** | |
* Returns the model object for an image. In this case a FMCType.Image. | |
* Should be overridden by other editors when using another meta model. | |
* | |
* @return The model object to be used. | |
*/ | |
protected Object getImageModelObject() { | |
return FMCType.Image; | |
} | |
/** | |
* Returns the minimum x,y coordinates of the shapes. | |
* | |
* @param shapes | |
* The shapes to analyze the minimum coordinates. | |
* @return The minimum coordinates x,y. | |
*/ | |
private ILocation getMinimumLocation(Object[] shapes) { | |
int minX = Integer.MAX_VALUE; | |
int minY = Integer.MAX_VALUE; | |
for (Object obj : shapes) { | |
if (obj instanceof Shape) { | |
Shape shape = (Shape) obj; | |
if (minX > shape.getGraphicsAlgorithm().getX()) | |
minX = shape.getGraphicsAlgorithm().getX(); | |
if (minY > shape.getGraphicsAlgorithm().getY()) | |
minY = shape.getGraphicsAlgorithm().getY(); | |
} | |
} | |
return new LocationImpl(minX, minY); | |
} | |
/** | |
* Is the targetContainer object contained in the shapes array? | |
* | |
* @param targetContainer The target container to search for. | |
* @param shapes The shapes array to analyze. | |
* @return | |
*/ | |
private boolean containsTargetContainer(Object targetContainer, | |
Object[] shapes) { | |
for (Object obj : shapes) { | |
if (targetContainer.equals(obj)) | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Pastes the pictogram elements into the diagram. | |
* | |
* @param context The paste context. | |
* @param p The point to paste the pictogram elements to. | |
* @param objects The objects to paste. | |
*/ | |
private void pastePictogramElements(IPasteContext context, Point p, | |
Object[] objects) { | |
Map<ILocation, Shape> shapeLocations = new HashMap<ILocation, Shape>(); | |
ILocation minimumLocation = getMinimumLocation(objects); | |
ContainerShape targetContainer = ((ContainerShape) context | |
.getPictogramElements()[0]); | |
List<Shape> originalShapes = new ArrayList<Shape>(); | |
List<Shape> copiedShapes = new ArrayList<Shape>(); | |
if (containsTargetContainer(targetContainer, objects)) | |
targetContainer = getDiagram(); | |
for (Object object : objects) { | |
if (object instanceof Shape) { | |
Shape copiedShape = (Shape) EcoreUtil.copy((EObject) object); | |
if (copiedShape instanceof ContainerShape) { | |
originalShapes.add((Shape) object); | |
copiedShapes.add(copiedShape); | |
ContainerShape originalContainer = (ContainerShape) object; | |
ContainerShape copiedContainer = (ContainerShape) copiedShape; | |
List<Shape> nestedOriginalShapes = new ArrayList<Shape>(); | |
List<Shape> nestedcopiedShapes = new ArrayList<Shape>(); | |
getAllNestedShapes(nestedOriginalShapes, | |
(originalContainer.getChildren())); | |
getAllNestedShapes(nestedcopiedShapes, | |
(copiedContainer.getChildren())); | |
copyConnections(nestedOriginalShapes, nestedcopiedShapes); | |
} | |
targetContainer.getChildren().add(copiedShape); | |
ILocation relativePosition = FMCUtil.getRelativePosition( | |
targetContainer, p.x, p.y); | |
shapeLocations.put(relativePosition, copiedShape); | |
copiedShape.getGraphicsAlgorithm().setX( | |
relativePosition.getX() - minimumLocation.getX() | |
+ copiedShape.getGraphicsAlgorithm().getX()); | |
copiedShape.getGraphicsAlgorithm().setY( | |
relativePosition.getY() - minimumLocation.getY() | |
+ copiedShape.getGraphicsAlgorithm().getY()); | |
if (FMCUtil.getBO(copiedShape) != null) { | |
EObject copy = EcoreUtil.copy(FMCUtil.getBO(copiedShape)); | |
addCopyToModel(copy); | |
copiedShape.getLink().getBusinessObjects().clear(); | |
copiedShape.getLink().getBusinessObjects().add(copy); | |
} | |
copyConnections(originalShapes, copiedShapes); | |
getDiagram().getChildren().add(copiedShape); | |
} | |
} | |
} | |
/** | |
* This method should be overridden when using alternative meta models. Does | |
* nothing in this case because no real meta model is used. | |
* | |
* @param copy | |
* The copy to be added to the model. | |
*/ | |
protected void addCopyToModel(EObject copy) { | |
// Do nothing | |
} | |
/** | |
* Returns all nested shapes recursively. | |
* | |
* @param nested | |
* The nested shapes result. | |
* @param shapes | |
* The shapes to be analyzed. | |
*/ | |
private void getAllNestedShapes(Collection<Shape> nested, | |
Collection<Shape> shapes) { | |
for (Shape shape : shapes) { | |
nested.add(shape); | |
if (shape instanceof ContainerShape) { | |
getAllNestedShapes(nested, | |
((ContainerShape) shape).getChildren()); | |
} | |
} | |
} | |
/** | |
* Copies the connections from originalShapes to copiedShapes | |
* | |
* @param originalShapes | |
* The original shapes. | |
* @param copiedShapes | |
* The copied shapes. | |
*/ | |
private void copyConnections(List<Shape> originalShapes, | |
List<Shape> copiedShapes) { | |
Collection<Connection> conToCopy = new HashSet<Connection>(); | |
for (Connection con : getDiagram().getConnections()) { | |
boolean startFound = false; | |
boolean endFound = false; | |
for (Shape shape : originalShapes) { | |
if (con.getStart() != null | |
&& shape.equals(con.getStart().getParent())) { | |
startFound = true; | |
} | |
if (con.getEnd() != null | |
&& shape.equals(con.getEnd().getParent())) { | |
endFound = true; | |
} | |
if (startFound && endFound) | |
break; | |
} | |
if (startFound && endFound) | |
conToCopy.add(con); | |
} | |
for (Connection connection : conToCopy) { | |
Connection copy = EcoreUtil.copy(connection); | |
Shape start = findCopy(originalShapes, copiedShapes, | |
(Shape) connection.getStart().getParent()); | |
Shape end = findCopy(originalShapes, copiedShapes, | |
(Shape) connection.getEnd().getParent()); | |
copy.setStart(start.getAnchors().get(0)); | |
copy.setEnd(end.getAnchors().get(0)); | |
getDiagram().getConnections().add(copy); | |
} | |
} | |
/** | |
* Finds the copy of the original in the copied shapes using the same index | |
* as the original. | |
* | |
* @param originalShapes | |
* The shapes to search for the original shape | |
* @param copiedShapes | |
* The copied shapes to find the copy in. | |
* @param original | |
* The original to be found in the originalShapes. | |
* @return The copy of the original using the same index. | |
*/ | |
private Shape findCopy(List<Shape> originalShapes, | |
List<Shape> copiedShapes, Shape original) { | |
return copiedShapes.get(originalShapes.indexOf(original)); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see | |
* org.eclipse.graphiti.features.impl.AbstractFeature#addGraphicalRepresentation | |
* (org.eclipse.graphiti.features.context.IAreaContext, java.lang.Object) | |
*/ | |
@Override | |
protected PictogramElement addGraphicalRepresentation(IAreaContext context, | |
Object newObject) { | |
if (context instanceof IAddContext) | |
return getFeatureProvider().addIfPossible((IAddContext) context); | |
else | |
return getFeatureProvider().addIfPossible( | |
new AddContext(context, newObject)); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see | |
* org.eclipse.graphiti.features.IPasteFeature#canPaste(org.eclipse.graphiti | |
* .features.context.IPasteContext) | |
*/ | |
@Override | |
public boolean canPaste(IPasteContext context) { | |
return true; | |
} | |
} |