blob: a0baa3ee8cc82806371b598e9215fbd2970dc925 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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.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;
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();
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)
{
action.run();
}
}
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);
}
}