/*****************************************************************************
* Copyright (c) 2010 CEA LIST.
*
*
* 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:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.menu.actions;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.diagram.ui.requests.SetAllBendpointRequest;
import org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx;
import org.eclipse.papyrus.uml.diagram.common.layout.DistributionConstants;
import org.eclipse.papyrus.uml.diagram.common.layout.LayoutUtils;
import org.eclipse.papyrus.uml.diagram.common.layout.LinkRepresentationForLayoutAction;
import org.eclipse.papyrus.uml.diagram.menu.Activator;
/**
*
* This class provides actions to set links vertical or horizontal, moving the anchor on one of its ends
*
*/
public class RouteAction {
/** the routing type */
private int routing = PositionConstants.NONE;
/** the selected elements */
private List<IGraphicalEditPart> selectedElements;
/** this list owning the link representation for this action */
private List<LinkRepresentationForLayoutAction> links;
/**
*
* Constructor.
*
* @param parameter
* the routing parameter
* @param selectedElements
* the selected elements for this action
*/
public RouteAction(String parameter, List<IGraphicalEditPart> selectedElements) {
this.selectedElements = selectedElements;
this.routing = getRoutingValue(parameter);
this.links = new ArrayList<LinkRepresentationForLayoutAction>();
calculateNewPosition();
}
/**
* Return the command for this action
* This command removes the bendpoints too.
*
* @return
* The command for the RouteAction
*/
public Command getCommand() {
CompoundCommand command = new CompoundCommand();
if(onlyConnectionEditPart(selectedElements) && this.routing != PositionConstants.NONE) {
for(LinkRepresentationForLayoutAction obj : links) {
if(onOppositeSides(obj)) {
Command cmd = obj.getCommand();
if(cmd != UnexecutableCommand.INSTANCE) {
command.add(cmd);
//we want no bendpoint, and keep the current source and target
Request noBendpoints = new SetAllBendpointRequest(RequestConstants.REQ_SET_ALL_BENDPOINT, new PointList(), null, null);
command.add(obj.getRepresentedLink().getCommand(noBendpoints));
}
}
}
}
return command.canExecute() ? command : UnexecutableCommand.INSTANCE;
}
/**
* Calculate the new position for anchor of the link
* Fill {@link #links} with the representation of the linkss
*/
protected void calculateNewPosition() {
for(Object current : selectedElements) {
if(current instanceof ConnectionEditPart) {
LinkRepresentationForLayoutAction link = new LinkRepresentationForLayoutAction((ConnectionEditPart)current);
EditPart anchorMovesOnEP = getEditPartForMovingAnchor((ConnectionEditPart)current);
if(anchorMovesOnEP != null) {
IFigure fig = ((GraphicalEditPart)current).getFigure();
Assert.isTrue(fig instanceof PolylineConnectionEx);
PolylineConnectionEx linkFigure = (PolylineConnectionEx)fig;
Point start = linkFigure.getStart();
Point end = linkFigure.getEnd();
linkFigure.translateToAbsolute(start);
linkFigure.translateToAbsolute(end);
Point movedAnchor = findMovingAnchor(start, end);
if(movedAnchor == null) {
break;//we can not continue
}
Point fixedAncher = (movedAnchor == start) ? end : start;
Point newLocation = getNewLocation(fixedAncher, movedAnchor);
link.setNewLocationFor(anchorMovesOnEP, newLocation);
links.add(link);
}
}
}
}
/**
* Calculate the new Position for the moving anchor
*
* @param fixedAnchor
* the fixed anchor of the link
* @param movedAnchor
* the moving anchor of the link
* @return
* the new location for the moving anchor
*/
protected Point getNewLocation(Point fixedAnchor, Point movedAnchor) {
Point delta = new Point();
if(routing == PositionConstants.LEFT || routing == PositionConstants.RIGHT) {
delta.setLocation(0, fixedAnchor.y - movedAnchor.y);
} else if(routing == PositionConstants.TOP || routing == PositionConstants.BOTTOM) {
delta.setLocation(fixedAnchor.x - movedAnchor.x, 0);
}
return movedAnchor.getTranslated(delta.x, delta.y);
}
protected EditPart getEditPartForMovingAnchor(ConnectionEditPart current) {
EditPart source = current.getSource();
EditPart target = current.getTarget();
IFigure fig = current.getFigure();
Assert.isTrue(fig instanceof PolylineConnectionEx);
PolylineConnectionEx linkFigure = (PolylineConnectionEx)fig;
Point start = linkFigure.getStart();
Point end = linkFigure.getEnd();
linkFigure.translateToAbsolute(start);
linkFigure.translateToAbsolute(end);
Point movedAnchor = findMovingAnchor(start, end);
if(movedAnchor == null) {
return null;
}
int sideSource = LayoutUtils.getAnchorPosition(source, movedAnchor);
int sideTarget = LayoutUtils.getAnchorPosition(target, movedAnchor);
if(sideSource != PositionConstants.NONE) {
return source;
} else if(sideTarget != PositionConstants.NONE) {
return target;
} else {
Activator.log.debug("I can't find the EditPart on which moves the anchor"); //$NON-NLS-1$
return null;
}
}
/**
* Return an int representing the wanted routing for this action
*
* @param param
* the routing parameter
* @return
* an int representing the wanted routing for this action
*/
protected int getRoutingValue(String param) {
if(param.equals(LayoutUtils.LEFT)) {
return PositionConstants.LEFT;
} else if(param.equals(LayoutUtils.RIGHT)) {
return PositionConstants.RIGHT;
} else if(param.equals(LayoutUtils.TOP)) {
return PositionConstants.TOP;
} else if(param.equals(LayoutUtils.BOTTOM)) {
return PositionConstants.BOTTOM;
}
return PositionConstants.NONE;
}
/**
* Test if the list is composed by {@link #onlyConnectionEditPart(List)}
*
* @param elementsToTest
* the elementsToTest
* @return
* <ul>
* <li> <code>true</code> if the list contains only {@link ConnectionEditPart}</li>
* <li> <code>false</code> if not</li>
* </ul>
*/
protected boolean onlyConnectionEditPart(List<IGraphicalEditPart> elementsToTest) {
for(IGraphicalEditPart current : elementsToTest) {
if(!(current instanceof ConnectionEditPart)) {
return false;
}
}
return true;
}
/**
* Return the point (between source and target) which will move with this action
*
* @param source
* the point representing the source of the link
* @param target
* the point representing the target of the link
* @return
* the point (between source and target) which will move with this action
*/
protected Point findMovingAnchor(Point source, Point target) {
Point movingAnchor = null;
switch(routing) {
case PositionConstants.LEFT: //the leftmost moves
if(source.x < target.x) {
movingAnchor = source;
} else {
movingAnchor = target;
}
break;
case PositionConstants.RIGHT: //the rightmost moves
if(source.x > target.x) {
movingAnchor = source;
} else {
movingAnchor = target;
}
break;
case PositionConstants.TOP: //the highest moves
if(source.y < target.y) {
movingAnchor = source;
} else {
movingAnchor = target;
}
break;
case PositionConstants.BOTTOM://the lowest moves
if(source.y > target.y) {
movingAnchor = source;
} else {
movingAnchor = target;
}
break;
default:
break;
}
if(movingAnchor == null) {
Activator.log.debug("I can't find the moving anchor"); //$NON-NLS-1$
}
return movingAnchor;
}
/**
* Test if the ends of the link are in opposition
*
* @param link
* the link to test
* @return
* <ul>
* <li> <code>true</code> if the ends of the link are in opposition</li>
* <li> <code>false</code> if not</li>
* </ul>
*/
protected boolean onOppositeSides(LinkRepresentationForLayoutAction link) {
int side1 = link.getSideOnSource();
int side2 = link.getSideOnTarget();
if(routing == PositionConstants.RIGHT || routing == PositionConstants.LEFT) {
if(DistributionConstants.verticalValuesList.contains(side1) && DistributionConstants.verticalValuesList.contains(side2)) {
return true;
}
} else if(routing == PositionConstants.TOP || routing == PositionConstants.BOTTOM) {
if(DistributionConstants.horizontalValuesList.contains(side1) && DistributionConstants.horizontalValuesList.contains(side2)) {
return true;
}
}
return false;
}
}