package org.eclipse.papyrus.uml.diagram.sequence.edit.policies; import java.util.ArrayList; import java.util.List; import org.eclipse.draw2d.Cursors; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Locator; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PrecisionRectangle; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.common.util.EList; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.Handle; import org.eclipse.gef.RequestConstants; import org.eclipse.gef.commands.Command; import org.eclipse.gef.handles.MoveHandle; import org.eclipse.gef.handles.MoveHandleLocator; import org.eclipse.gef.handles.RelativeHandleLocator; import org.eclipse.gef.handles.ResizeHandle; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gef.tools.ResizeTracker; import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ResizableEditPolicyEx; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CombinedFragmentEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart.LifelineFigure; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil; import org.eclipse.swt.graphics.Cursor; import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.Lifeline; public class LifelineSelectionEditPolicy extends ResizableEditPolicyEx { public LifelineSelectionEditPolicy() { setResizeDirections(PositionConstants.NORTH | PositionConstants.SOUTH | PositionConstants.WEST | PositionConstants.EAST); } protected List<?> createSelectionHandles() { final LifelineEditPart host = (LifelineEditPart) getHost(); final LifelineFigure primaryShape = host.getPrimaryShape(); // resizable in at least one direction List<Handle> list = new ArrayList<Handle>(); // createMoveHandle(list); Locator locator = new MoveHandleLocator( primaryShape.getFigureLifelineNameContainerFigure()); MoveHandle moveHandle = new MoveHandle((GraphicalEditPart) getHost(), locator); moveHandle.setCursor(Cursors.SIZEALL); list.add(moveHandle); createResizeHandle(list, PositionConstants.NORTH); final IFigure fig = primaryShape .getFigureLifelineNameContainerFigure(); createResizeHandle(host, list, fig,PositionConstants.WEST); createResizeHandle(host, list, fig,PositionConstants.EAST); createResizeHandle(list, PositionConstants.SOUTH); return list; } private void createResizeHandle(LifelineEditPart host, List<Handle> list, IFigure fig, int location) { Locator locator = new RelativeHandleLocator(fig, location); Cursor cursor = Cursors .getDirectionalCursor(location, fig.isMirrored()); ResizeHandle westResizer = new ResizeHandle((GraphicalEditPart) host, locator, cursor); ResizeTracker resizeTracker = new ResizeTracker(host, location); westResizer.setDragTracker(resizeTracker); list.add(westResizer); } protected void showChangeBoundsFeedback(ChangeBoundsRequest request) { IFigure feedback = getDragSourceFeedbackFigure(); PrecisionRectangle rect = new PrecisionRectangle( getInitialFeedbackBounds().getCopy()); getHostFigure().translateToAbsolute(rect); boolean skipMinSize = false; //Only enable horizontal dragging on lifelines(except lifelines that are result of a create message). //https://bugs.eclipse.org/bugs/show_bug.cgi?id=364688 if (this.getHost() instanceof LifelineEditPart) { skipMinSize = true; LifelineEditPart lifelineEP = (LifelineEditPart) this.getHost(); if (!SequenceUtil.isCreateMessageEndLifeline(lifelineEP)) { request.getMoveDelta().y = 0; } //keepNameLabelBounds(lifelineEP, request, rect); // restrict child size within parent bounds keepInParentBounds(lifelineEP, request, rect); changeCombinedFragmentBounds(request, lifelineEP); } Point left = rect.getLeft(); Point right = rect.getRight(); rect.translate(request.getMoveDelta()); rect.resize(request.getSizeDelta()); IFigure f = getHostFigure(); Dimension min = f.getMinimumSize().getCopy(); Dimension max = f.getMaximumSize().getCopy(); // IMapMode mmode = MapModeUtil.getMapMode(f); // min.height = mmode.LPtoDP(min.height); // min.width = mmode.LPtoDP(min.width); // max.height = mmode.LPtoDP(max.height); // max.width = mmode.LPtoDP(max.width); getHostFigure().translateToAbsolute(min); getHostFigure().translateToAbsolute(max); // In manual mode, there is no minimal width, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=383723 if (min.width > rect.width && !skipMinSize){ if( request.getMoveDelta().x > 0 && request.getSizeDelta().width != 0){ rect.x = right.x - min.width ; request.getMoveDelta().x = rect.x -left.x; } rect.width = min.width; } else if (max.width < rect.width) rect.width = max.width; if (min.height > rect.height) rect.height = min.height; else if (max.height < rect.height) rect.height = max.height; feedback.translateToRelative(rect); feedback.setBounds(rect); } private void keepNameLabelBounds(LifelineEditPart lifelineEP, ChangeBoundsRequest request, PrecisionRectangle rect) { PrecisionRectangle size = getMovedRectangle(rect, request); Dimension preferSize = lifelineEP.getPrimaryShape().getFigureLifelineNameContainerFigure().getPreferredSize(-1, -1).getCopy(); getHostFigure().translateToAbsolute(preferSize); // handle scale size if(size.width < preferSize.width){ request.getSizeDelta().width = preferSize.width - rect.width ; if( request.getMoveDelta().x > 0) request.getMoveDelta().x = rect.width - preferSize.width; } } protected Rectangle getCurrentConstraintFor(GraphicalEditPart child) { IFigure fig = child.getFigure(); return (Rectangle) fig.getParent().getLayoutManager() .getConstraint(fig); } private void keepInParentBounds(LifelineEditPart lifelineEP, ChangeBoundsRequest request, PrecisionRectangle rect) { if (lifelineEP.getParent() instanceof LifelineEditPart){ LifelineEditPart parent = (LifelineEditPart)lifelineEP.getParent() ; Rectangle p = parent.getFigure().getBounds().getCopy(); parent.getFigure().translateToAbsolute(p); PrecisionRectangle c = getMovedRectangle(rect, request); Dimension preferSize = getHostFigure().getPreferredSize(); getHostFigure().translateToAbsolute(preferSize); // handle scale size if (request.getType().equals(RequestConstants.REQ_RESIZE)) { switch (request.getResizeDirection()) { case PositionConstants.WEST: if (c.getLeft().x <= p.getLeft().x) { // exceed left edge int delta = (p.getLeft().x - c.getLeft().x); request.getMoveDelta().x += delta; request.getSizeDelta().width -= delta; } break; case PositionConstants.EAST: if (c.getRight().x + request.getSizeDelta().width >= p.getRight().x) { // exceed right edge int delta = (c.getRight().x - p.getRight().x ); request.getSizeDelta().width -= delta; } break; } } else { if (c.getLeft().x <= p.getLeft().x) { // exceed left edge int delta = (p.getLeft().x - c.getLeft().x); request.getMoveDelta().x += delta; } else if (c.getRight().x >= p.getRight().x) { // exceed right edge int delta = (c.getRight().x - p.getRight().x ); request.getMoveDelta().x -= delta; } } // check lifeline intersect with each other c = getMovedRectangle(rect , request); Rectangle other = getLifelineIntersectBounds(lifelineEP, parent, request, c); if (other != null) { if (request.getSizeDelta().width == 0) { // move only if(request.getMoveDelta().x > 0){ // move right request.getMoveDelta().x = other.getLeft().x - rect.getRight().x; } else { request.getMoveDelta().x = other.getRight().x - rect.getLeft().x; } } else { if (request.getMoveDelta().x == 0) { // resize right edge request.getSizeDelta().width = other.getLeft().x - rect.getRight().x; } else { // resize left edge request.getMoveDelta().x = other.getRight().x - rect.getLeft().x; request.getSizeDelta().width = - request.getMoveDelta().x ; } } } } } private Rectangle getLifelineIntersectBounds(LifelineEditPart lifelineEP, LifelineEditPart parent, ChangeBoundsRequest request, PrecisionRectangle rect) { List children = parent.getChildren(); for(Object o : children) if(o instanceof LifelineEditPart && o != lifelineEP){ LifelineEditPart p = (LifelineEditPart)o; Rectangle bounds = p.getFigure().getBounds().getCopy(); p.getFigure().translateToAbsolute(bounds); if(bounds.intersects(rect)){ return bounds; } } return null; } private PrecisionRectangle getMovedRectangle(PrecisionRectangle rect , ChangeBoundsRequest request ){ PrecisionRectangle c = rect.getPreciseCopy(); c.translate(request.getMoveDelta()); c.resize(request.getSizeDelta()); return c; } private void changeCombinedFragmentBounds(ChangeBoundsRequest request, LifelineEditPart lifelineEP) { if(request.getMoveDelta().x > 0) // move right return; View shape = (View) lifelineEP.getModel(); Lifeline element = (Lifeline) shape.getElement(); EList<InteractionFragment> covereds = element.getCoveredBys(); EditPart parent = lifelineEP.getParent(); List<?> children = parent.getChildren(); for (Object obj : children) { if(obj instanceof CombinedFragmentEditPart){ CombinedFragmentEditPart et = (CombinedFragmentEditPart) obj; View sp = (View) et.getModel(); if (!covereds.contains(sp.getElement())) { continue; } changeCombinedFragmentBounds( request, et, lifelineEP); } } } Point maxMoveDelta; @Override protected void eraseChangeBoundsFeedback(ChangeBoundsRequest request) { super.eraseChangeBoundsFeedback(request); maxMoveDelta = null; } void changeCombinedFragmentBounds(ChangeBoundsRequest request, CombinedFragmentEditPart cep, LifelineEditPart lifelineEP){ Rectangle rect = getTransformedRectangle(cep, request); if(rect.x <= 0){ if(maxMoveDelta != null) request.getMoveDelta().x = maxMoveDelta.x; else{ Point p = new Point(Math.abs(rect.x), 0 ); cep.getFigure().translateToAbsolute(p); request.getMoveDelta().x = Math.min(0, request.getMoveDelta().x + p.x ) ; maxMoveDelta = request.getMoveDelta().getCopy(); } } } private Rectangle getTransformedRectangle(CombinedFragmentEditPart cep, ChangeBoundsRequest request) { Rectangle rect = new PrecisionRectangle(cep.getFigure().getBounds()); cep.getFigure().translateToAbsolute(rect); rect = request.getTransformedRectangle(rect); cep.getFigure().translateToRelative(rect); return rect; } }