| /******************************************************************************* |
| * Copyright (c) 2007, 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.wst.xsd.ui.internal.commands; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.draw2d.Figure; |
| import org.eclipse.draw2d.FreeformLayout; |
| import org.eclipse.draw2d.Graphics; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.Polyline; |
| import org.eclipse.draw2d.PositionConstants; |
| import org.eclipse.draw2d.RoundedRectangle; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.PointList; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| import org.eclipse.gef.EditPartViewer; |
| import org.eclipse.gef.GraphicalEditPart; |
| import org.eclipse.gef.editparts.ScalableRootEditPart; |
| import org.eclipse.gef.requests.ChangeBoundsRequest; |
| import org.eclipse.wst.xsd.ui.internal.actions.MoveXSDBaseAction; |
| import org.eclipse.wst.xsd.ui.internal.adapters.XSDBaseAdapter; |
| import org.eclipse.wst.xsd.ui.internal.adt.design.editparts.BaseFieldEditPart; |
| import org.eclipse.wst.xsd.ui.internal.common.commands.BaseCommand; |
| import org.eclipse.wst.xsd.ui.internal.design.editparts.ConnectableEditPart; |
| import org.eclipse.wst.xsd.ui.internal.design.editparts.TargetConnectionSpacingFigureEditPart; |
| import org.eclipse.wst.xsd.ui.internal.design.editparts.XSDBaseFieldEditPart; |
| import org.eclipse.wst.xsd.ui.internal.design.figures.GenericGroupFigure; |
| import org.eclipse.xsd.XSDConcreteComponent; |
| import org.w3c.dom.Element; |
| |
| public abstract class BaseDragAndDropCommand extends BaseCommand |
| { |
| protected static int ABOVE_IS_CLOSER = 0; |
| protected static int BELOW_IS_CLOSER = 1; |
| |
| protected EditPartViewer viewer; |
| protected ChangeBoundsRequest request; |
| protected boolean canExecute; |
| protected GraphicalEditPart target; |
| |
| protected GraphicalEditPart leftSiblingEditPart; |
| protected GraphicalEditPart rightSiblingEditPart; |
| protected Point location; |
| |
| protected ConnectableEditPart parentEditPart; |
| protected XSDConcreteComponent previousRefComponent = null, nextRefComponent = null, xsdComponentToDrag; |
| protected XSDBaseFieldEditPart itemToDrag; |
| protected Rectangle originalLocation; |
| protected Polyline polyLine; |
| |
| protected MoveXSDBaseAction action; |
| protected List targetSpacesList = new ArrayList(); |
| protected int closerSibling; |
| |
| public BaseDragAndDropCommand(EditPartViewer viewer, ChangeBoundsRequest request) |
| { |
| this.viewer = viewer; |
| this.request = request; |
| } |
| |
| protected abstract void setup(); |
| |
| /** |
| * Provides the DOM element associated with the parent XSD component. |
| * This element is used in the the undo/redo mechanism. |
| * @return the DOM element associated with the parent XSD component. |
| */ |
| protected abstract Element getElement(); |
| |
| public PointList getConnectionPoints(Rectangle draggedFigureBounds) |
| { |
| PointList pointList = null; |
| if (target != null && itemToDrag != null && parentEditPart != null) |
| { |
| pointList = getConnectionPoints(parentEditPart, itemToDrag, draggedFigureBounds); |
| } |
| return pointList != null ? pointList : new PointList(); |
| } |
| |
| // This method supports the preview connection line function related to drag and drop |
| // |
| public PointList getConnectionPoints(ConnectableEditPart parentEditPart, BaseFieldEditPart childRefEditPart, Rectangle draggedFigureBounds) |
| { |
| PointList pointList = new PointList(); |
| int[] data = new int[1]; |
| Point a = getConnectionPoint(parentEditPart, childRefEditPart, data); |
| if (a != null) |
| { |
| int draggedFigureBoundsY = draggedFigureBounds.y + draggedFigureBounds.height/2; |
| |
| pointList.addPoint(a); |
| |
| if (data[0] == 0) // insert between 2 items |
| { |
| int x = a.x + 5; |
| pointList.addPoint(new Point(x, a.y)); |
| pointList.addPoint(new Point(x, draggedFigureBoundsY)); |
| pointList.addPoint(new Point(draggedFigureBounds.x, draggedFigureBoundsY)); |
| } |
| else // insert at first or last position |
| { |
| pointList.addPoint(new Point(a.x, draggedFigureBoundsY)); |
| pointList.addPoint(new Point(draggedFigureBounds.x, draggedFigureBoundsY)); |
| } |
| } |
| return pointList; |
| } |
| |
| // This method supports the preview connection line function related to drag and drop |
| // |
| protected Point getConnectionPoint(ConnectableEditPart parentEditPart, BaseFieldEditPart childRefEditPart, int[] data) |
| { |
| Point point = null; |
| List childList = parentEditPart.getChildren(); |
| if (parentEditPart.getFigure() instanceof GenericGroupFigure && childList.size() > 0) |
| { |
| point = new Point(); |
| |
| Rectangle r = getConnectedEditPartConnectionBounds(parentEditPart); |
| point.x = r.x + r.width; |
| point.y = r.y + r.height/2; |
| } |
| return point; |
| } |
| |
| protected Rectangle getConnectedEditPartConnectionBounds(ConnectableEditPart editPart) |
| { |
| return getZoomedBounds(((GenericGroupFigure)editPart.getFigure()).getIconFigure().getBounds()); |
| } |
| |
| public void redo() |
| { |
| } |
| |
| public void undo() |
| { |
| } |
| |
| public void execute() |
| { |
| if (canExecute) |
| { |
| // Wrap the drag and drop operation for easy undo and redo. |
| beginRecording(this.getElement()); |
| action.run(); |
| endRecording(); |
| } |
| } |
| |
| public boolean canExecute() |
| { |
| return canExecute; |
| } |
| |
| protected void commonSetup(List siblings, GraphicalEditPart movingEditPart) |
| { |
| closerSibling = ABOVE_IS_CLOSER; |
| int pointerYLocation = location.y; |
| int index; |
| |
| for (index = 0; index < siblings.size(); index++) |
| { |
| GraphicalEditPart sibling = (GraphicalEditPart) siblings.get(index); |
| if (sibling instanceof BaseFieldEditPart) |
| { |
| int siblingYLocation = getZoomedBounds(sibling.getFigure().getBounds()).getCenter().y; |
| |
| if (siblingYLocation > pointerYLocation) |
| { |
| rightSiblingEditPart = sibling; |
| if (index > 0) |
| { |
| leftSiblingEditPart = (GraphicalEditPart) siblings.get(index - 1); |
| } |
| |
| if (leftSiblingEditPart != null && Math.abs(getZoomedBounds(leftSiblingEditPart.getFigure().getBounds()).getCenter().y - pointerYLocation) > Math.abs(siblingYLocation - pointerYLocation)) |
| { |
| closerSibling = BELOW_IS_CLOSER; |
| } |
| break; |
| } |
| } |
| } |
| |
| boolean isHandled = handleFirstAndLastDropTargets(index, siblings); |
| if (!isHandled) |
| handleOtherTargets(index); |
| |
| calculateLeftAndRightXSDComponents(); |
| |
| xsdComponentToDrag = (XSDConcreteComponent) ((XSDBaseAdapter) itemToDrag.getModel()).getTarget(); |
| } |
| |
| protected void calculateLeftAndRightXSDComponents() |
| { |
| if (leftSiblingEditPart instanceof XSDBaseFieldEditPart) |
| { |
| Object leftModel = ((XSDBaseFieldEditPart) leftSiblingEditPart).getModel(); |
| previousRefComponent = null; |
| if (leftModel instanceof XSDBaseAdapter) |
| { |
| XSDBaseAdapter leftAdapter = (XSDBaseAdapter) leftModel; |
| previousRefComponent = (XSDConcreteComponent) leftAdapter.getTarget(); |
| } |
| } |
| |
| if (rightSiblingEditPart instanceof XSDBaseFieldEditPart) |
| { |
| Object rightModel = ((XSDBaseFieldEditPart) rightSiblingEditPart).getModel(); |
| nextRefComponent = null; |
| if (rightModel instanceof XSDBaseAdapter) |
| { |
| XSDBaseAdapter rightAdapter = (XSDBaseAdapter) rightModel; |
| nextRefComponent = (XSDConcreteComponent) rightAdapter.getTarget(); |
| } |
| } |
| } |
| |
| protected boolean handleFirstAndLastDropTargets(int index, List siblings) |
| { |
| // Handle case where you drop to first position |
| if (index == 0 && siblings.size() > 0) |
| { |
| leftSiblingEditPart = null; |
| rightSiblingEditPart = (GraphicalEditPart) siblings.get(0); |
| closerSibling = BELOW_IS_CLOSER; |
| } |
| // Handle case where you drop to last position |
| else if (index > 0 && index == siblings.size()) |
| { |
| leftSiblingEditPart = (GraphicalEditPart) siblings.get(index - 1); |
| rightSiblingEditPart = null; |
| } |
| return false; |
| } |
| |
| protected void handleOtherTargets(int index) |
| { |
| int in = 0; |
| ConnectableEditPart previousModelEditPart = null; |
| for (Iterator i = targetSpacesList.iterator(); i.hasNext();) |
| { |
| Object o = i.next(); |
| previousModelEditPart = parentEditPart; |
| TargetConnectionSpacingFigureEditPart sp = (TargetConnectionSpacingFigureEditPart) o; |
| if (sp.getParent() instanceof ConnectableEditPart) |
| parentEditPart = (ConnectableEditPart)sp.getParent(); |
| else |
| parentEditPart = null; |
| in++; |
| if (in > index) |
| { |
| if (closerSibling == ABOVE_IS_CLOSER) |
| { |
| parentEditPart = previousModelEditPart; |
| } |
| break; |
| } |
| } |
| } |
| |
| protected List calculateFieldEditParts() |
| { |
| List list = target.getParent().getChildren(); |
| List listOfFields = new ArrayList(); |
| for (Iterator i = list.iterator(); i.hasNext();) |
| { |
| Object o = i.next(); |
| if (o instanceof BaseFieldEditPart) |
| { |
| listOfFields.add(o); |
| } |
| } |
| return listOfFields; |
| } |
| |
| protected PointList drawLines(Polyline polyLine) |
| { |
| PointList pointList = new PointList(); |
| |
| if (leftSiblingEditPart != null) |
| { |
| Rectangle leftRectangle = getZoomedBounds(leftSiblingEditPart.getFigure().getBounds()); |
| int xCoord = leftRectangle.x; |
| int yCoord = leftRectangle.y; |
| int height = leftRectangle.height; |
| int width = leftRectangle.width; |
| |
| // Draw left end line |
| addLineToPolyline(polyLine, xCoord, yCoord + height + 3, xCoord, yCoord + height - 3); |
| addLineToPolyline(polyLine, xCoord, yCoord + height - 3, xCoord, yCoord + height); |
| |
| // Draw horizontal line |
| addLineToPolyline(polyLine, xCoord, yCoord + height, xCoord + width, yCoord + height); |
| |
| // Draw right end line |
| addLineToPolyline(polyLine, xCoord + width, yCoord + height, xCoord + width, yCoord + height - 3); |
| addLineToPolyline(polyLine, xCoord + width, yCoord + height, xCoord + width, yCoord + height + 3); |
| } |
| else if (rightSiblingEditPart != null) |
| { |
| Rectangle rightRectangle = getZoomedBounds(rightSiblingEditPart.getFigure().getBounds()); |
| int xCoord = rightRectangle.x; |
| int yCoord = rightRectangle.y; |
| int width = rightRectangle.width; |
| |
| // Draw left end line |
| addLineToPolyline(polyLine, xCoord, yCoord + 3, xCoord, yCoord - 3); |
| addLineToPolyline(polyLine, xCoord, yCoord - 3, xCoord, yCoord); |
| |
| // Draw horizontal line |
| addLineToPolyline(polyLine, xCoord, yCoord, xCoord + width, yCoord); |
| |
| // Draw right end line |
| addLineToPolyline(polyLine, xCoord + width, yCoord, xCoord + width, yCoord - 3); |
| addLineToPolyline(polyLine, xCoord + width, yCoord, xCoord + width, yCoord + 3); |
| } |
| |
| return pointList; |
| } |
| |
| protected Polyline addLineToPolyline(Polyline polyline, int x1, int y1, int x2, int y2) |
| { |
| polyline.addPoint(new Point(x1, y1)); |
| polyline.addPoint(new Point(x2, y2)); |
| |
| return polyline; |
| } |
| |
| public IFigure getFeedbackFigure() |
| { |
| Figure panel = new Figure(); |
| panel.setLayoutManager(new FreeformLayout()); |
| panel.setOpaque(false); |
| |
| Polyline feedbackFigure = new Polyline(); |
| feedbackFigure.setLineWidth(2); |
| drawLines(feedbackFigure); |
| originalLocation = new Rectangle(feedbackFigure.getBounds()); |
| panel.add(feedbackFigure); |
| |
| polyLine = new Polyline(); |
| polyLine.setLineStyle(Graphics.LINE_DASHDOT); |
| polyLine.setLineWidth(1); |
| panel.add(polyLine); |
| |
| panel.setBounds(originalLocation); |
| |
| addConnectorToParent(panel); |
| |
| if (parentEditPart != null && parentEditPart.getFigure() instanceof GenericGroupFigure) |
| { |
| GenericGroupFigure fig = (GenericGroupFigure)parentEditPart.getFigure(); |
| Rectangle iconBounds = getZoomedBounds(fig.getIconFigure().getBounds()); |
| RoundedRectangle roundedRectangle = new RoundedRectangle(); |
| roundedRectangle.setFill(false); |
| roundedRectangle.setOpaque(true); |
| // roundedRectangle.setBounds(new Rectangle(iconBounds.x, iconBounds.y, iconBounds.width - 1, iconBounds.height - 1)); |
| roundedRectangle.setBounds(iconBounds); |
| panel.add(roundedRectangle); |
| } |
| return panel; |
| } |
| |
| protected void addConnectorToParent(IFigure p) |
| { |
| Rectangle r = originalLocation.getCopy(); |
| Rectangle pBounds = r.getCopy(); |
| PointList pointList = getConnectionPoints(r); |
| |
| if (pointList != null && pointList.size() > 0) |
| { |
| polyLine.setPoints(pointList); |
| Point firstPoint = pointList.getFirstPoint(); |
| if (firstPoint != null) |
| { |
| pBounds = pBounds.getUnion(new Rectangle(firstPoint.x, firstPoint.y, 1, 1)); |
| } |
| } |
| |
| if (parentEditPart != null) |
| { |
| if (parentEditPart.getFigure() instanceof GenericGroupFigure) |
| { |
| GenericGroupFigure fig = (GenericGroupFigure)parentEditPart.getFigure(); |
| Rectangle iconBounds = getZoomedBounds(fig.getIconFigure().getBounds()); |
| pBounds = pBounds.getUnion(iconBounds); |
| } |
| } |
| |
| p.setBounds(pBounds); |
| p.validate(); |
| } |
| |
| public Point getZoomedPoint(Point p) |
| { |
| double factor = ((ScalableRootEditPart)viewer.getRootEditPart()).getZoomManager().getZoom(); |
| |
| int x = (int)Math.round(p.x * factor); |
| int y = (int)Math.round(p.y * factor); |
| |
| return new Point(x, y); |
| } |
| |
| public Rectangle getZoomedBounds(Rectangle r) |
| { |
| double factor = ((ScalableRootEditPart)viewer.getRootEditPart()).getZoomManager().getZoom(); |
| |
| int x = (int)Math.round(r.x * factor); |
| int y = (int)Math.round(r.y * factor); |
| int width = (int)Math.round(r.width * factor); |
| int height = (int)Math.round(r.height * factor); |
| |
| return new Rectangle(x, y, width, height); |
| } |
| |
| protected void handleKeyboardDragAndDrop(XSDBaseFieldEditPart leftField, XSDBaseFieldEditPart rightField, int direction) |
| { |
| target = leftField; |
| if (direction == PositionConstants.SOUTH) |
| { |
| if (itemToDrag == target) |
| return; |
| target = rightField; |
| } |
| this.location = null; |
| if (target != null) |
| this.location = target.getFigure().getBounds().getCenter(); |
| } |
| } |