/****************************************************************************** * 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; } }