/******************************************************************************* * Copyright (c) 2000, 2009 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.gef.editpolicies; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.Widget; import org.eclipse.gef.EditPart; import org.eclipse.gef.Request; import org.eclipse.gef.TreeEditPart; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gef.requests.CreateRequest; import org.eclipse.gef.requests.DropRequest; /** * An EditPolicy for handling ADDS, MOVES, and CREATES on a {@link TreeEditPart}. * <P> * This EditPolicy is responsible for displaying the insertion feedback in the Tree during * the appropriate interactions. * <P> * This EditPolicy factors the {@link #getCommand(Request)} into three different abstract * methods which subclasses must implement. * @since 2.0 */ public abstract class TreeContainerEditPolicy extends AbstractEditPolicy { private static TreeItem[] oldSelection; /** * Returns a Command for adding the children to the container. * @param request the Request to add. * @return Command <code>null</code> or a Command to perform the add */ protected abstract Command getAddCommand(ChangeBoundsRequest request); /** * Returns a Command for creating the object inside the container. * @param request the CreateRequest * @return Command <code>null</code> or a Command to perform the create */ protected abstract Command getCreateCommand(CreateRequest request); /** * Returns a Command for moving the children within the container. * @param request the Request to move * @return Command <code>null</code> or a Command to perform the move */ protected abstract Command getMoveChildrenCommand(ChangeBoundsRequest request); private void eraseDropFeedback(Request req) { getTree().setInsertMark(null, true); restoreSelection(); } /** * @see org.eclipse.gef.EditPolicy#eraseTargetFeedback(Request) */ public void eraseTargetFeedback(Request req) { if (req.getType().equals(REQ_MOVE) || req.getType().equals(REQ_ADD) || req.getType().equals(REQ_CREATE)) eraseDropFeedback(req); } /** * Calculates the index of the TreeItem at given point. * @param pt the Point in the Viewer * @return the index of the TreeItem */ protected final int findIndexOfTreeItemAt(org.eclipse.draw2d.geometry.Point pt) { int index = -1; TreeItem item = findTreeItemAt(pt); if (item != null) { index = getHost().getChildren().indexOf(item.getData()); if (index >= 0 && !isInUpperHalf(item.getBounds(), pt)) index++; } return index; } /** * Calculates the <code>TreeItem</code> at a specified {@link * org.eclipse.draw2d.geometry.Point}. * @param pt the draw2d Point * @return <code>null</code> or the TreeItem */ protected final TreeItem findTreeItemAt(org.eclipse.draw2d.geometry.Point pt) { return getTree().getItem(new Point(pt.x, pt.y)); } /** * @see org.eclipse.gef.EditPolicy#getCommand(Request) */ public Command getCommand(Request req) { if (req.getType().equals(REQ_MOVE_CHILDREN)) return getMoveChildrenCommand((ChangeBoundsRequest)req); if (req.getType().equals(REQ_ADD)) return getAddCommand((ChangeBoundsRequest)req); if (req.getType().equals(REQ_CREATE)) return getCreateCommand((CreateRequest)req); return null; } /** * Returns the host EditPart when appropriate. Targeting is done by checking if the mouse * is clearly over the host's TreeItem. * @see org.eclipse.gef.EditPolicy#getTargetEditPart(Request) */ public EditPart getTargetEditPart(Request req) { if (req.getType().equals(REQ_ADD) || req.getType().equals(REQ_MOVE) || req.getType().equals(REQ_CREATE)) { DropRequest drop = (DropRequest) req; Point where = new Point(drop.getLocation().x, drop.getLocation().y); Widget widget = ((TreeEditPart) getHost()).getWidget(); if (widget instanceof Tree) return getHost(); TreeItem treeitem = (TreeItem) widget; Rectangle bounds = treeitem.getBounds(); int fudge = bounds.height / 5; Rectangle inner = new Rectangle( bounds.x, bounds.y + fudge, bounds.width, bounds.height - (treeitem.getExpanded() ? 0 : fudge * 2)); //Point is either outside the Treeitem, or inside the inner Rect. if (!bounds.contains(where) || inner.contains(where)) return getHost(); } return null; } private Tree getTree() { Widget widget = ((TreeEditPart)getHost()).getWidget(); if (widget instanceof Tree) return (Tree)widget; else return ((TreeItem)widget).getParent(); } private void insertMarkAfterLastChild(TreeItem[] children) { if (children != null && children.length > 0) { TreeItem item = children[ children.length - 1 ]; getTree().setInsertMark(item, false); } } private boolean isInUpperHalf(Rectangle rect, org.eclipse.draw2d.geometry.Point pt) { Rectangle tempRect = new Rectangle(rect.x, rect.y, rect.width, rect.height / 2); return tempRect.contains(new Point(pt.x, pt.y)); } private void restoreSelection() { if (oldSelection != null) { try { getTree().setSelection(oldSelection); } finally { oldSelection = null; } } } private void showDropFeedback(DropRequest request) { Widget hostWidget = ((TreeEditPart)getHost()).getWidget(); Tree tree = getTree(); if (oldSelection == null) { oldSelection = tree.getSelection(); TreeItem newSelection[]; if (hostWidget instanceof Tree) { newSelection = new TreeItem[0]; } else { /* * if parent item is out of the visible bounds, do not select * it, as the selection causes the viewer to scroll which * changes the insert location. */ TreeItem item = (TreeItem) hostWidget; if(item.getBounds().y < 0) { oldSelection = null; newSelection = new TreeItem[0]; } else { newSelection = new TreeItem[] { item }; } } tree.setSelection(newSelection); } org.eclipse.draw2d.geometry.Point pt = request.getLocation(); TreeItem item = findTreeItemAt(pt); if (item == null) { if (hostWidget == tree) { insertMarkAfterLastChild(tree.getItems()); } } else if (item == hostWidget) { tree.setInsertMark(null, true); } else { boolean before = isInUpperHalf(item.getBounds(), pt); tree.setInsertMark(item, before); } } /** * @see org.eclipse.gef.EditPolicy#showTargetFeedback(Request) */ public void showTargetFeedback(Request req) { if (req.getType().equals(REQ_MOVE) || req.getType().equals(REQ_ADD) || req.getType().equals(REQ_CREATE)) showDropFeedback((DropRequest)req); } }