blob: 3bfec7cfa81738c044615f45bcfc7f3872af307a [file] [log] [blame]
/*******************************************************************************
* <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;
}
}