/****************************************************************************** * Copyright (c) 2004, 2006 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation ****************************************************************************/ package org.eclipse.gmf.runtime.diagram.ui.editpolicies; import java.util.List; import org.eclipse.draw2d.IFigure; 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.gef.GraphicalEditPart; import org.eclipse.gef.Handle; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gmf.runtime.diagram.ui.internal.handles.RotateHandle; import org.eclipse.gmf.runtime.diagram.ui.internal.tools.RotateTracker; import org.eclipse.gmf.runtime.gef.ui.internal.requests.RotateShapeRequest; /** * A rotatable editpolicy for rotating fork and join itparts * It rotates the figure if diagonal handlers are dragged and * resizes the figure otherwise as defined by the superclass * * @author oboyko */ public class RotatableShapeEditPolicy extends ResizableShapeEditPolicy { // how much should be the mice moved to rotate the figure private final static int DEFAULT_TOLERANCE = 6; /* * Create the selection handles for edit parts that have Rotatable Edit Policy * installed on them, i.e. Forks and Joins from Activity and State Machine diagrams * (non-Javadoc) * @see org.eclipse.gef.editpolicies.SelectionHandlesEditPolicy#createSelectionHandles() */ protected List createSelectionHandles() { setResizeDirections(PositionConstants.EAST | PositionConstants.SOUTH | PositionConstants.WEST | PositionConstants.NORTH); List selectionhandles = super.createSelectionHandles(); GraphicalEditPart part = (GraphicalEditPart) getHost(); selectionhandles.add(createRotationHandle(part, PositionConstants.SOUTH_EAST)); selectionhandles.add(createRotationHandle(part, PositionConstants.SOUTH_WEST)); selectionhandles.add(createRotationHandle(part, PositionConstants.NORTH_WEST)); selectionhandles.add(createRotationHandle(part, PositionConstants.NORTH_EAST)); return selectionhandles; } /** * Create rotate handle with a rotate tracker * @param owner the owner edit part * @param direction the handle direction * @return the handle */ protected Handle createRotationHandle(GraphicalEditPart owner, int direction) { RotateHandle handle = new RotateHandle(owner, direction); handle.setDragTracker( new RotateTracker(owner, direction)); return handle; } /** * Shows or updates feedback for a change bounds request that is seen as rotation * @param request the request */ protected void showChangeBoundsFeedback(ChangeBoundsRequest request) { // If the figure is being rotated draw the rotation feedback if ( isRotationRequired(request)) { // Get current feedback IFigure feedback = getDragSourceFeedbackFigure(); if (doRotation(request)) { // Get the absolute coordinates for rotated figure PrecisionRectangle rect = getAbsoluteRotatedBounds(); // Draw the rotated figure in the feedback feedback.translateToRelative(rect); feedback.setBounds(rect); } else { // Get the absolute coordinates for initial and rotated figure PrecisionRectangle initFigure = getAbsoluteInitialBounds(); // Draw the initial figure in the feedback feedback.translateToRelative(initFigure); feedback.setBounds(initFigure); } } else { // otherwise the figure is being resized super.showChangeBoundsFeedback(request); } } /* * Returns PrecisionRectangle obtained from the rotation by 90 deg. of an argument rectangle * with respect to it's geometrical centre * @param Rectangle r * @return PrecisionRectangle rect obtained from rotation of r */ private PrecisionRectangle rotateRectangle(Rectangle r) { PrecisionRectangle rect = new PrecisionRectangle(r); if (isVertical(r)) { rect.setX(rect.preciseX-rect.preciseHeight/2.0+rect.preciseWidth/2.0); rect.setY(rect.preciseY+rect.preciseHeight/2.0-rect.preciseWidth/2.0); } else { rect.setX(rect.preciseX+rect.preciseWidth/2.0-rect.preciseHeight/2.0); rect.setY(rect.preciseY-rect.preciseWidth/2.0+rect.preciseHeight/2.0); } transposePrecisionRectangleSize(rect); return rect; } /* * Check whether the bar (or figure) is vertical or horizontal * @param Rectangle - the bounds of the figure * @return true if figure is vertical, fasle if figure is horizontal */ private boolean isVertical(Rectangle r) { return r.height>r.width; } /* * Transposes PrecisionRectangle's size * @param PrecisionRectangle * @return PrecisionRectangle with transposed size */ private void transposePrecisionRectangleSize(PrecisionRectangle r) { double height = r.preciseHeight; r.setHeight(r.preciseWidth); r.setWidth(height); } /* * Returns if figure must be rotated based on the info in the request, i.e. * diagonal resize direction and rotatable edit parts are selected. * @param change bounds request * @return true if figure must be rotated */ private boolean isRotationRequired(ChangeBoundsRequest request) { return request instanceof RotateShapeRequest ? ((RotateShapeRequest) request).shouldRotate() : false; } /* * Returns the command contribution for the given resize request. By default, the request * is redispatched to the host's parent as a {@link * org.eclipse.gef.RequestConstants#REQ_RESIZE_CHILDREN}. The parent's editpolicies * determine how to perform the resize based on the layout manager in use. * @param request the resize request * @return the command contribution obtained from the parent * @see org.eclipse.gef.editpolicies.ResizableEditPolicy#getResizeCommand(org.eclipse.gef.requests.ChangeBoundsRequest) */ protected Command getResizeCommand(ChangeBoundsRequest request) { // if the figure needs to be rotated set the command with the proper data if (isRotationRequired(request)) { ChangeBoundsRequest req = new ChangeBoundsRequest(REQ_RESIZE_CHILDREN); req.setEditParts(getHost()); // fake resizing and movement to resize the figure if mice is moved far enough if (doRotation(request)) { // Get the absolute coordinates for initial and rotated figure PrecisionRectangle rect = getAbsoluteRotatedBounds(); PrecisionRectangle initFigure = getAbsoluteInitialBounds(); req.setMoveDelta (new Point(rect.preciseX - initFigure.preciseX, rect.preciseY - initFigure.preciseY)); req.setSizeDelta (new Dimension(rect.width - initFigure.width, rect.height - initFigure.height)); } else { // otherwise SizeDelta and MoveDelta must be 0s req.setSizeDelta(new Dimension()); req.setMoveDelta(new Point()); } req.setLocation(request.getLocation()); req.setExtendedData(request.getExtendedData()); req.setResizeDirection(request.getResizeDirection()); return getHost().getParent().getCommand(req); } else { // otherwise the figure is being resized return super.getResizeCommand(request); } } /* * Based on the size delta from the request determines whether the EditPart must be rotated or * remain as it is */ private boolean doRotation(ChangeBoundsRequest request) { return Math.abs(request.getSizeDelta().width) > DEFAULT_TOLERANCE || Math.abs(request.getSizeDelta().height) > DEFAULT_TOLERANCE; } /* * Returns the bounds of the initial figure in the absolute coordinates */ private PrecisionRectangle getAbsoluteInitialBounds() { // store the initial figure PrecisionRectangle initFigure = new PrecisionRectangle(getInitialFeedbackBounds().getCopy()); getHostFigure().translateToAbsolute(initFigure); return initFigure; } /* * Returns the bounds of the rotated initial figure with respect to its geometrical centre * in absolute coordinates */ private PrecisionRectangle getAbsoluteRotatedBounds() { // store the rotated figure PrecisionRectangle rect = new PrecisionRectangle(rotateRectangle(getInitialFeedbackBounds().getCopy())); getHostFigure().translateToAbsolute(rect); return rect; } }