blob: ff216fc3bc22d41afe94595f7109aeaddf097db0 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2004, 2010 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.actions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
import org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPage;
/**
* Provides support for action which add an attached shapes to another shape.
* Puts the added shape in direct edit mode after all the shapes and connections
* are created.
*
* @author jcorchis
*/
public abstract class AttachShapeAction
extends DiagramAction {
/**
* Constructor
*
* @param workbenchPage
* the active workbenchPage
*/
public AttachShapeAction(IWorkbenchPage workbenchPage) {
super(workbenchPage);
}
/**
* Method selectAddedObject. Selects Select the newly added shape view by
* default
*
* @param request
* the request object that holds a reference for the newly
* created object
* @param viewer
* the viewer that contains the shapes to be selected. The shapes
* correspond to the newly created object.
*/
protected void selectAddedObject(EditPartViewer viewer,
CreateRequest request) {
final Object model = request.getNewObject();
if (model == null || !(model instanceof Collection))
return;
final Iterator models = ((Collection) model).iterator();
final List editparts = new ArrayList();
while (models.hasNext()) {
IAdaptable viewAdapter = (IAdaptable) models.next();
if (viewAdapter != null) {
Object editPart = viewer.getEditPartRegistry().get(
viewAdapter.getAdapter(View.class));
if (editPart != null)
editparts.add(editPart);
}
}
if (!editparts.isEmpty()) {
viewer.setSelection(new StructuredSelection(editparts));
// automatically put the first shape into edit-mode
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
EditPart editPart = (EditPart) editparts.get(0);
editPart.performRequest(new Request(
RequestConstants.REQ_DIRECT_EDIT));
}
});
}
}
/**
* Determines the location of for the shape to be created in relation to the
* some other shape.
*
* @param editParts
* the existing editparts of the shapes whose location is used to
* determine the location of the to be created shape
* @return Point the point representing the location of the to be created
* shape
*/
protected Point getLocation(List editParts) {
Point referenceLocation = new Point(0, 0);
Rect compoundBounds = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE,
Integer.MIN_VALUE, Integer.MIN_VALUE);
for (int i = 0; i < editParts.size(); i++) {
GraphicalEditPart part = (GraphicalEditPart) editParts.get(i);
Rectangle bounds = null;
if (part.getFigure() instanceof PolylineConnectionEx)
bounds = ((PolylineConnectionEx) part.getFigure())
.getSimpleBounds();
else
bounds = part.getFigure().getBounds();
compoundBounds = compoundRectangle(compoundBounds, bounds);
}
referenceLocation = new Point(
(compoundBounds.x1 + compoundBounds.x2) / 2, compoundBounds.y1);
GraphicalEditPart part = (GraphicalEditPart) editParts.get(0);
int vertOffset = MapModeUtil.getMapMode(part.getFigure()).DPtoLP(100);
Point location = new Point();
location.x = referenceLocation.x;
location.y = referenceLocation.y - vertOffset;
// convert the location to screen coordinates as that is what the
// creation command expects
// this is done so that the new node don;t hide up in the scrollpane of
// the shapecompartment.
if ((location.y < 0)
&& (part.getParent() instanceof ShapeCompartmentEditPart)) {
location.y = referenceLocation.y;
location.x = part.getFigure().getBounds().getRight().x
+ vertOffset;
}
part.getFigure().translateToAbsolute(location);
return location;
}
/**
* Builds a compound rectangle out of contributing rectangles
*
* @param base
* the base rectangle to start with
* @param added
* the newly added rectangle to be compounded
* @return Rect the resulting compound rectangle
*
*/
private Rect compoundRectangle(Rect base, Rectangle added) {
if (added == null)
return base;
if (added.x + added.width > base.x2)
base.x2 = added.x + added.width;
if (added.y + added.height > base.y2)
base.y2 = added.y + added.height;
if (added.x < base.x1)
base.x1 = added.x;
if (added.y < base.y1)
base.y1 = added.y;
return base;
}
private class Rect {
public int x1, y1, x2, y2;
Rect(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gmf.runtime.common.ui.action.AbstractActionHandler#isSelectionListener()
*/
protected boolean isSelectionListener() {
return true;
}
/**
* Return null since this action doesn't use request to execute its
* commands.
*/
protected Request createTargetRequest() {
return null;
}
/**
* Return the first non {@link ShapeEditPart} and non
* {@link ConnectionEditPart} instance in the supplied editparts editpart
* hierarchy.
*
* @param editPart
* starting editpart
* @return an editpart the first non <code>ShapeEditPart</code> non
* <code>ConnectionEditPart</code> it found traversing the
* hierarchy upwards.
*/
protected EditPart getContainer(EditPart editPart) {
EditPart walker = editPart;
while (walker != null
&& (walker instanceof ShapeEditPart || walker instanceof ConnectionEditPart)) {
walker = walker.getParent();
}
if (walker instanceof RootEditPart) {
return ((RootEditPart) walker).getContents();
}
return walker;
}
}