/*******************************************************************************
* Copyright (c) 2000, 2010, 2012 IBM Corporation, Gerhardt Informatics Kft. 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
* Gerhardt Informatics Kft. - GEFGWT port
*******************************************************************************/
package org.eclipse.gef.editpolicies;
import java.util.List;
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.draw2d.geometry.Translatable;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.requests.AlignmentRequest;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;
/**
* For use with <code>LayoutManager</code> that require a <i>constraint</i>.
* ConstrainedLayoutEditPolicy understands
* {@link RequestConstants#REQ_ALIGN_CHILDREN} in addition to the Requests
* handled in the superclass.
*
* @author hudsonr
* @author anyssen
* @since 2.0
*/
public abstract class ConstrainedLayoutEditPolicy extends LayoutEditPolicy {
/**
* Constant being used to indicate that upon creation (or during move) a
* size was not specified.
*
* @since 3.7
*/
protected static final Dimension UNSPECIFIED_SIZE = new Dimension();
/**
* Returns the <code>Command</code> to perform an Add with the specified
* child and constraint. The constraint has been converted from a draw2d
* constraint to an object suitable for the model by calling
* {@link #translateToModelConstraint(Object)}.
*
* @param request
* the ChangeBoundsRequest
* @param child
* the EditPart of the child being added
* @param constraint
* the model constraint, after being
* {@link #translateToModelConstraint(Object) translated}
* @return the Command to add the child
*
* @since 3.7
*/
protected Command createAddCommand(ChangeBoundsRequest request,
EditPart child, Object constraint) {
return createAddCommand(child, constraint);
}
/**
* Returns the <code>Command</code> to perform an Add with the specified
* child and constraint. The constraint has been converted from a draw2d
* constraint to an object suitable for the model by calling
* {@link #translateToModelConstraint(Object)}.
*
* @param child
* the EditPart of the child being added
* @param constraint
* the model constraint, after being
* {@link #translateToModelConstraint(Object) translated}
* @return the Command to add the child
* @deprecated Use
* {@link #createAddCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
* @nooverride Overwrite
* {@link #createAddCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
* @noreference Use
* {@link #createAddCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
*/
protected Command createAddCommand(EditPart child, Object constraint) {
return null;
}
/**
* The request is now made available when creating the change constraint
* command. By default, this method invokes the old
* {@link ConstrainedLayoutEditPolicy#createChangeConstraintCommand(EditPart, Object)
* method}.
*
* @param request
* the ChangeBoundsRequest
* @param child
* the EditPart of the child being changed
* @param constraint
* the new constraint, after being
* {@link #translateToModelConstraint(Object) translated}
* @return A Command to change the constraints of the given child as
* specified in the given request
* @see ConstrainedLayoutEditPolicy#createChangeConstraintCommand(EditPart,
* Object)
* @since 3.0
*/
protected Command createChangeConstraintCommand(
ChangeBoundsRequest request, EditPart child, Object constraint) {
return createChangeConstraintCommand(child, constraint);
}
/**
* Returns the <code>Command</code> to change the specified child's
* constraint. The constraint has been converted from a draw2d constraint to
* an object suitable for the model. Clients should overwrite
* {@link #createChangeConstraintCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
*
* @param child
* the EditPart of the child being changed
* @param constraint
* the new constraint, after being
* {@link #translateToModelConstraint(Object) translated}
* @return Command
* @see #createChangeConstraintCommand(ChangeBoundsRequest, EditPart,
* Object)
* @deprecated Use
* {@link #createChangeConstraintCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
* @nooverride Overwrite
* {@link #createChangeConstraintCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
* @noreference Use
* {@link #createChangeConstraintCommand(ChangeBoundsRequest, EditPart, Object)}
* instead.
*/
protected Command createChangeConstraintCommand(EditPart child,
Object constraint) {
return null;
}
/**
* A {@link ResizableEditPolicy} is used by default for children. Subclasses
* may override this method to supply a different EditPolicy.
*
* @see org.eclipse.gef.editpolicies.LayoutEditPolicy#createChildEditPolicy(EditPart)
*/
protected EditPolicy createChildEditPolicy(EditPart child) {
return new ResizableEditPolicy();
}
/**
* Overrides <code>getAddCommand()</code> to generate the proper constraint
* for each child being added. Once the constraint is calculated,
* {@link #createAddCommand(EditPart,Object)} is called. Subclasses must
* implement this method.
*
* @see org.eclipse.gef.editpolicies.LayoutEditPolicy#getAddCommand(Request)
*/
protected Command getAddCommand(Request generic) {
ChangeBoundsRequest request = (ChangeBoundsRequest) generic;
List editParts = request.getEditParts();
CompoundCommand command = new CompoundCommand();
command.setDebugLabel("Add in ConstrainedLayoutEditPolicy");//$NON-NLS-1$
GraphicalEditPart child;
for (int i = 0; i < editParts.size(); i++) {
child = (GraphicalEditPart) editParts.get(i);
command.add(createAddCommand(
request,
child,
translateToModelConstraint(getConstraintFor(request, child))));
}
return command.unwrap();
}
/**
* Returns the command to align a group of children. By default, this is
* treated the same as a resize, and
* {@link #getResizeChildrenCommand(ChangeBoundsRequest)} is returned.
*
* @param request
* the AligmentRequest
* @return the command to perform alignment
*/
protected Command getAlignChildrenCommand(AlignmentRequest request) {
return getResizeChildrenCommand(request);
}
/**
* Factors out RESIZE and ALIGN requests, otherwise calls <code>super</code>
* .
*
* @see org.eclipse.gef.EditPolicy#getCommand(Request)
*/
public Command getCommand(Request request) {
if (REQ_RESIZE_CHILDREN.equals(request.getType()))
return getResizeChildrenCommand((ChangeBoundsRequest) request);
if (REQ_ALIGN_CHILDREN.equals(request.getType()))
return getAlignChildrenCommand((AlignmentRequest) request);
return super.getCommand(request);
}
/**
* Generates a draw2d constraint object for the given
* <code>ChangeBoundsRequest</code> and child EditPart by delegating to
* {@link #getConstraintFor(Request, GraphicalEditPart, Rectangle)}.
*
* The rectangle being passed over to
* {@link #getConstraintFor(Request, GraphicalEditPart, Rectangle)} is
* calculated based on the child figure's current bounds and the
* ChangeBoundsRequest's move and resize deltas. It is made layout-relative
* by using {@link #translateFromAbsoluteToLayoutRelative(Translatable)}
* before calling
* {@link #getConstraintFor(Request, GraphicalEditPart, Rectangle)}.
*
* @param request
* the ChangeBoundsRequest
* @param child
* the child EditPart for which the constraint should be
* generated
* @return the draw2d constraint
*/
protected Object getConstraintFor(ChangeBoundsRequest request,
GraphicalEditPart child) {
Rectangle locationAndSize = new PrecisionRectangle(child.getFigure()
.getBounds());
child.getFigure().translateToAbsolute(locationAndSize);
locationAndSize = request.getTransformedRectangle(locationAndSize);
translateFromAbsoluteToLayoutRelative(locationAndSize);
return getConstraintFor(request, child, locationAndSize);
}
/**
* Responsible of generating a draw2d constraint for the given Rectangle,
* which represents the already transformed (layout-relative) position and
* size of the given Request.
*
* By default, this method delegates to {@link #getConstraintFor(Point)} or
* {@link #getConstraintFor(Rectangle)}, dependent on whether the size of
* the rectangle is an {@link #UNSPECIFIED_SIZE} or not.
*
* Subclasses may overwrite this method in case they need the request or the
* edit part (which will of course not be set during creation) to calculate
* a layout constraint for the request.
*
* @param rectangle
* the Rectangle relative to the {@link #getLayoutOrigin() layout
* origin}
* @return the constraint
* @since 3.7
*/
protected Object getConstraintFor(Request request, GraphicalEditPart child,
Rectangle rectangle) {
if (UNSPECIFIED_SIZE.equals(rectangle.getSize())) {
return getConstraintFor(rectangle.getLocation());
}
return getConstraintFor(rectangle);
}
/**
* Generates a draw2d constraint given a <code>Point</code>. This method is
* called during creation, when only a mouse location is available, as well
* as during move, in case no resizing is involved.
*
* @param point
* the Point relative to the {@link #getLayoutOrigin() layout
* origin}
* @return the constraint
*/
protected abstract Object getConstraintFor(Point point);
/**
* Generates a draw2d constraint given a <code>Rectangle</code>. This method
* is called during most operations.
*
* @param rect
* the Rectangle relative to the {@link #getLayoutOrigin() layout
* origin}
* @return the constraint
*/
protected abstract Object getConstraintFor(Rectangle rect);
/**
* Generates a draw2d constraint for the given <code>CreateRequest</code> by
* delegating to
* {@link #getConstraintFor(Request, GraphicalEditPart, Rectangle)}.
*
* If the CreateRequest has a size, is used during size-on-drop creation, a
* Rectangle of the request's location and size is passed with the
* delegation. Otherwise, a rectangle with the request's location and an
* empty size (0,0) is passed over.
* <P>
* The CreateRequest's location is relative to the Viewer. The location is
* made layout-relative by using
* {@link #translateFromAbsoluteToLayoutRelative(Translatable)} before
* calling {@link #getConstraintFor(Request, GraphicalEditPart, Rectangle)}.
*
* @param request
* the CreateRequest
* @return a draw2d constraint
*/
protected Object getConstraintFor(CreateRequest request) {
Rectangle locationAndSize = null;
if (request.getSize() == null || request.getSize().isEmpty()) {
locationAndSize = new PrecisionRectangle(request.getLocation(),
UNSPECIFIED_SIZE);
} else {
locationAndSize = new PrecisionRectangle(request.getLocation(),
request.getSize());
}
translateFromAbsoluteToLayoutRelative(locationAndSize);
return getConstraintFor(request, null, locationAndSize);
}
/**
* Returns the correct rectangle bounds for the new clone's location.
*
* @param part
* the graphical edit part representing the object to be cloned.
* @param request
* the ChangeBoundsRequest that knows where to place the new
* object.
* @return the bounds that will be used for the new object.
* @deprecated Use
* {@link #getConstraintFor(ChangeBoundsRequest, GraphicalEditPart)}
* instead.
* @nooverride This method is not intended to be re-implemented or extended
* by clients.
* @noreference This method is not intended to be referenced by clients.
*/
protected Object getConstraintForClone(GraphicalEditPart part,
ChangeBoundsRequest request) {
// anyssen: The code executed herein was functionally the same
// as that in getConstraintFor(ChangeBoundsRequest, GraphicalEditPart),
// despite it was erroneously missing a call to
// getLayoutContainer().translateFromParent(), which is needed
// to translate the part's figure's bounds into a coordinate
// local to the client area of the layout container.
return getConstraintFor(request, part);
}
/**
* Converts a constraint from the format used by LayoutManagers, to the form
* stored in the model.
*
* @param figureConstraint
* the draw2d constraint
* @return the model constraint
*/
protected Object translateToModelConstraint(Object figureConstraint) {
return figureConstraint;
}
/**
* Returns the <code>Command</code> to resize a group of children.
*
* @param request
* the ChangeBoundsRequest
* @return the Command
*/
protected Command getResizeChildrenCommand(ChangeBoundsRequest request) {
return getChangeConstraintCommand(request);
}
/**
* Returns the <code>Command</code> for changing bounds for a group of
* children.
*
* @param request
* the ChangeBoundsRequest
* @return the Command
*
* @since 3.7
*/
protected Command getChangeConstraintCommand(ChangeBoundsRequest request) {
CompoundCommand resize = new CompoundCommand();
Command c;
GraphicalEditPart child;
List children = request.getEditParts();
for (int i = 0; i < children.size(); i++) {
child = (GraphicalEditPart) children.get(i);
c = createChangeConstraintCommand(
request,
child,
translateToModelConstraint(getConstraintFor(request, child)));
resize.add(c);
}
return resize.unwrap();
}
/**
* Returns the <code>Command</code> to move a group of children. By default,
* move is treated the same as a resize.
*
* @see org.eclipse.gef.editpolicies.LayoutEditPolicy#getMoveChildrenCommand(Request)
*/
protected Command getMoveChildrenCommand(Request request) {
// By default, move and resize are treated the same for constrained
// layouts.
return getResizeChildrenCommand((ChangeBoundsRequest) request);
}
}