/*****************************************************************************
* Copyright (c) 2010 CEA
*
*
* 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:
* Atos Origin - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.sequence.edit.policies;
import java.util.Collections;
import java.util.List;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Polyline;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.handles.MoveHandle;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.NonResizableEditPolicyEx;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.NonResizableLabelEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.internal.figures.LabelHelper;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
import org.eclipse.gmf.runtime.diagram.ui.tools.DragEditPartsTrackerEx;
import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.notation.View;
/**
* This class offers the same features as {@link NonResizableLabelEditPolicy}, except that move is privileged instead of drag and drop.
* It is useful for edit parts on messages.
*/
public class MoveableNonResizableLabelEditPolicy extends NonResizableEditPolicyEx {
@Override
protected List<?> createSelectionHandles() {
MoveHandle mh = new MoveHandle((GraphicalEditPart)getHost());
mh.setBorder(null);
mh.setDragTracker(createSelectionHandleDragTracker());
return Collections.singletonList(mh);
}
private Polyline tether = null;
protected void eraseChangeBoundsFeedback(ChangeBoundsRequest request) {
super.eraseChangeBoundsFeedback(request);
if(tether != null)
removeFeedback(tether);
tether = null;
}
protected IFigure createDragSourceFeedbackFigure() {
IFigure feedback = super.createDragSourceFeedbackFigure();
tether = new Polyline();
tether.setLineStyle(Graphics.LINE_DASHDOT);
tether.setForegroundColor(((IGraphicalEditPart)getHost()).getFigure().getForegroundColor());
addFeedback(tether);
return feedback;
}
/**
* Calculates a point located at the middel of the parent connection
*
* @return the point
*/
private Point getReferencePoint() {
if(getHost().getParent() instanceof AbstractConnectionEditPart) {
PointList ptList = ((Connection)((ConnectionEditPart)getHost().getParent()).getFigure()).getPoints();
Point refPoint = PointListUtilities.calculatePointRelativeToLine(ptList, 0, 50, true);
return refPoint;
} else if(getHost().getParent() instanceof GraphicalEditPart) {
return ((AbstractGraphicalEditPart)getHost().getParent()).getFigure().getBounds().getCenter();
}
return null;
}
protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
super.showChangeBoundsFeedback(request);
IFigure p = getDragSourceFeedbackFigure();
Rectangle r = p.getBounds();
Point refPoint = getReferencePoint();
// translate the feedback figure
PrecisionRectangle rect = new PrecisionRectangle(getInitialFeedbackBounds().getCopy());
getHostFigure().translateToAbsolute(rect);
rect.translate(request.getMoveDelta());
rect.resize(request.getSizeDelta());
p.translateToRelative(rect);
p.setBounds(rect);
Rectangle centerMain = null;
// TODO: remove this hack. We should be using the reference point for
// the teher end, however,
// the reference point is causing miscaculation when positioning. This
// has to be redone in version 2.
if(((IGraphicalEditPart)getHost().getParent()).getFigure() instanceof Connection) {
centerMain = new Rectangle(refPoint.x, refPoint.y, 0, 0);
getHostFigure().translateToAbsolute(centerMain);
p.translateToRelative(centerMain);
} else {
centerMain = ((IGraphicalEditPart)getHost().getParent()).getFigure().getBounds().getCopy();
centerMain.translate(centerMain.width / 2, centerMain.height / 2);
getHostFigure().translateToAbsolute(centerMain);
p.translateToRelative(centerMain);
}
PrecisionRectangle ref = new PrecisionRectangle(centerMain);
Point midTop = new Point(r.x + r.width / 2, r.y);
Point midBottom = new Point(r.x + r.width / 2, r.y + r.height);
Point midLeft = new Point(r.x, r.y + r.height / 2);
Point midRight = new Point(r.x + r.width, r.y + r.height / 2);
Point startPoint = midTop;
int x = r.x + r.width / 2 - refPoint.x;
int y = r.y + r.height / 2 - refPoint.y;
if(y > 0 && y > x && y > -x)
startPoint = midTop;
else if(y < 0 && y < x && y < -x)
startPoint = midBottom;
else if(x < 0 && y > x && y < -x)
startPoint = midRight;
else
startPoint = midLeft;
tether.setStart(startPoint);
tether.setEnd(ref.getLocation());
}
protected Command getMoveCommand(ChangeBoundsRequest request) {
GraphicalEditPart editPart = (GraphicalEditPart)getHost();
Point refPoint = getReferencePoint();
// translate the feedback figure
PrecisionRectangle rect = new PrecisionRectangle(getInitialFeedbackBounds().getCopy());
getHostFigure().translateToAbsolute(rect);
rect.translate(request.getMoveDelta());
rect.resize(request.getSizeDelta());
getHostFigure().translateToRelative(rect);
Point normalPoint = LabelHelper.offsetFromRelativeCoordinate(getHostFigure(), rect, refPoint);
ICommand moveCommand = new SetBoundsCommand(editPart.getEditingDomain(), DiagramUIMessages.MoveLabelCommand_Label_Location, new EObjectAdapter((View)editPart.getModel()), normalPoint);
return new ICommandProxy(moveCommand);
}
/**
* Overridden to use a customized drag tracker for the handles. The <code>isMove()</code> method of the drag tracker needs to be overridden
* as the parent of the label and connection will not be the same as the
* target editpart, instead it returns true always since labels can only be
* moved and not resized.
*
* @return a drag tracker
*/
protected DragTracker createSelectionHandleDragTracker() {
return new DragEditPartsTrackerEx(getHost()) {
protected boolean isMove() {
return true;
}
};
}
}