blob: 72c27a645286ae3aefc3fd921a8b054841c776ad [file] [log] [blame]
/*******************************************************************************
* <copyright>
*
* Copyright (c) 2005, 2011 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.graphiti.features.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.IMoveShapeContext;
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.FreeFormConnection;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
/**
* The Class DefaultMoveShapeFeature.
*/
public class DefaultMoveShapeFeature extends AbstractMoveShapeFeature {
/**
* Creates a new {@link DefaultMoveShapeFeature}.
*
* @param fp
* the feature provider
*/
public DefaultMoveShapeFeature(IFeatureProvider fp) {
super(fp);
}
/**
* Sublasses can override this method.
*
* @return true if moving to negative coordinates should not be possible
*/
protected boolean avoidNegativeCoordinates() {
return false;
}
public boolean canMoveShape(IMoveShapeContext context) {
return context.getSourceContainer() != null
&& context.getSourceContainer().equals(context.getTargetContainer());
}
public void moveShape(IMoveShapeContext context) {
preMoveShape(context);
moveAllBendpoints(context);
internalMove(context);
postMoveShape(context);
}
/**
* Move all bendpoints. Move bendpoints within a container shape.
*
* @param context
* the context
*/
protected void moveAllBendpoints(IMoveShapeContext context) {
Shape shapeToMove = context.getShape();
int x = context.getX();
int y = context.getY();
int deltaX = x - shapeToMove.getGraphicsAlgorithm().getX();
int deltaY = y - shapeToMove.getGraphicsAlgorithm().getY();
if (deltaX != 0 || deltaY != 0) {
List<FreeFormConnection> connectionList = new ArrayList<FreeFormConnection>();
FreeFormConnection[] containerConnections = calculateContainerConnections(context);
for (int i = 0; i < containerConnections.length; i++) {
FreeFormConnection cc = containerConnections[i];
if (!connectionList.contains(cc)) {
connectionList.add(cc);
}
}
FreeFormConnection[] connectedConnections = calculateConnectedConnections(context);
for (int i = 0; i < connectedConnections.length; i++) {
FreeFormConnection cc = connectedConnections[i];
if (!connectionList.contains(cc)) {
connectionList.add(cc);
}
}
for (FreeFormConnection conn : connectionList) {
moveAllBendpointsOnFFConnection((FreeFormConnection) conn, deltaX, deltaY);
}
}
}
/**
* Post move shape.
*
* @param context
* the context
*/
protected void postMoveShape(IMoveShapeContext context) {
}
/**
* Pre move shape.
*
* @param context
* the context
*/
protected void preMoveShape(IMoveShapeContext context) {
}
/**
* Internal move.
*
* @param context
* the context
*/
protected void internalMove(IMoveShapeContext context) {
if (!getUserDecision()) {
return;
}
Shape shapeToMove = context.getShape();
ContainerShape oldContainerShape = context.getSourceContainer();
ContainerShape newContainerShape = context.getTargetContainer();
int x = context.getX();
int y = context.getY();
if (oldContainerShape != newContainerShape) {
// remember selection, because it is lost when temporarily removing
// the shapes.
PictogramElement[] currentSelection = getDiagramBehavior().getDiagramContainer()
.getSelectedPictogramElements();
// the following is a workaround due to an MMR bug
if (oldContainerShape != null) {
Collection<Shape> children = oldContainerShape.getChildren();
if (children != null) {
children.remove(shapeToMove);
}
}
shapeToMove.setContainer(newContainerShape);
if (shapeToMove.getGraphicsAlgorithm() != null) {
Graphiti.getGaService().setLocation(shapeToMove.getGraphicsAlgorithm(), x, y,
avoidNegativeCoordinates());
}
// restore selection
getDiagramBehavior().getDiagramContainer().setPictogramElementsForSelection(currentSelection);
} else { // move within the same container
if (shapeToMove.getGraphicsAlgorithm() != null) {
Graphiti.getGaService().setLocation(shapeToMove.getGraphicsAlgorithm(), x, y,
avoidNegativeCoordinates());
}
}
}
private FreeFormConnection[] calculateContainerConnections(IMoveShapeContext context) {
FreeFormConnection[] ret = new FreeFormConnection[0];
if (!(context.getShape() instanceof ContainerShape)) {
return ret;
}
List<FreeFormConnection> retList = new ArrayList<FreeFormConnection>();
Shape shapeToMove = context.getShape();
int x = context.getX();
int y = context.getY();
int deltaX = x - shapeToMove.getGraphicsAlgorithm().getX();
int deltaY = y - shapeToMove.getGraphicsAlgorithm().getY();
if (deltaX != 0 || deltaY != 0) {
List<Anchor> anchorsFrom = getAnchors(shapeToMove);
List<Anchor> anchorsTo = new ArrayList<Anchor>(anchorsFrom);
for (Anchor anchorFrom : anchorsFrom) {
Collection<Connection> outgoingConnections = anchorFrom.getOutgoingConnections();
for (Connection connection : outgoingConnections) {
for (Anchor anchorTo : anchorsTo) {
Collection<Connection> incomingConnections = anchorTo.getIncomingConnections();
if (incomingConnections.contains(connection)) {
if (connection instanceof FreeFormConnection) {
retList.add((FreeFormConnection) connection);
}
}
}
}
}
}
return retList.toArray(ret);
}
private FreeFormConnection[] calculateConnectedConnections(IMoveShapeContext context) {
List<FreeFormConnection> retList = new ArrayList<FreeFormConnection>();
Shape shapeToMove = context.getShape();
int x = context.getX();
int y = context.getY();
int deltaX = x - shapeToMove.getGraphicsAlgorithm().getX();
int deltaY = y - shapeToMove.getGraphicsAlgorithm().getY();
if (deltaX != 0 || deltaY != 0) {
List<Anchor> anchors = getAnchors(shapeToMove);
PictogramElement[] selectedPictogramElements = getDiagramBehavior().getDiagramContainer()
.getSelectedPictogramElements();
if (selectedPictogramElements != null) {
for (int i = 0; i < selectedPictogramElements.length; i++) {
PictogramElement selPe = selectedPictogramElements[i];
if (selPe instanceof Shape) {
Shape selShape = (Shape) selPe;
for (Anchor toAnchor : getAnchors(selShape)) {
EList<Connection> incomingConnections = toAnchor.getIncomingConnections();
for (Connection inConn : incomingConnections) {
if (inConn instanceof FreeFormConnection) {
Anchor startAnchor = inConn.getStart();
if (anchors.contains(startAnchor)) {
retList.add((FreeFormConnection) inConn);
}
}
}
}
}
}
}
}
return retList.toArray(new FreeFormConnection[0]);
}
private void moveAllBendpointsOnFFConnection(FreeFormConnection connection, int deltaX, int deltaY) {
List<Point> points = connection.getBendpoints();
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
int oldX = point.getX();
int oldY = point.getY();
points.set(i, Graphiti.getGaCreateService().createPoint(oldX + deltaX, oldY + deltaY));
}
}
private List<Anchor> getAnchors(Shape theShape) {
List<Anchor> ret = new ArrayList<Anchor>();
ret.addAll(theShape.getAnchors());
if (theShape instanceof ContainerShape) {
ContainerShape containerShape = (ContainerShape) theShape;
List<Shape> children = containerShape.getChildren();
for (Shape shape : children) {
if (shape instanceof ContainerShape) {
ret.addAll(getAnchors((ContainerShape) shape));
} else {
ret.addAll(shape.getAnchors());
}
}
}
return ret;
}
}