/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui.cursortool;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
/**
* The default implementation draws a selection box, but this can be overridden
* (even to draw nothing).
*/
public abstract class DragTool extends AbstractCursorTool {
public static final int DEFAULT_VIEW_CLICK_BUFFER = 2;
private int viewClickBuffer = DEFAULT_VIEW_CLICK_BUFFER;
/** Modify using #setSource */
protected Coordinate modelSource = null;
/** Modify using #setDestination */
protected Coordinate modelDestination = null;
private boolean dragApproved = false;
/**
* Begins handling of the drag. Subclasses can prevent handling of the drag
* by overriding this method and not calling it.
*/
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
dragApproved = true;
try {
setViewSource(e.getPoint());
} catch (NoninvertibleTransformException x) {
getPanel().getContext().handleThrowable(x);
}
//Probably doesn't make sense to snap the source. Note that MoveSelectedItem's
//override of #snap assumes that it is only used on the destination. [Jon Aquino]
}
/**
* A click is converted into a box by being expanded by this amount in the
* four directions.
*/
protected void setViewClickBuffer(int clickBuffer) {
this.viewClickBuffer = clickBuffer;
}
protected boolean wasClick() {
return getModelSource().equals(getModelDestination());
}
protected Envelope getBoxInModelCoordinates()
throws NoninvertibleTransformException {
double minX = Math.min(getModelSource().x, getModelDestination().x);
double maxX = Math.max(getModelSource().x, getModelDestination().x);
double minY = Math.min(getModelSource().y, getModelDestination().y);
double maxY = Math.max(getModelSource().y, getModelDestination().y);
if (wasClick()) {
minX -= modelClickBuffer();
maxX += modelClickBuffer();
minY -= modelClickBuffer();
maxY += modelClickBuffer();
}
return new Envelope(minX, maxX, minY, maxY);
}
protected double modelClickBuffer() {
return viewClickBuffer / getPanel().getViewport().getScale();
}
public void mouseDragged(MouseEvent e) {
try {
if (!dragApproved) {
//dragApproved will be false if:
// -- the drag began outside the panel
// -- a subclass wanted to prevent handling of the drag by overriding
// #mousePressed and not calling it; for example, EditDelineationTool.
//[Jon Aquino]
return;
}
setViewDestination(e.getPoint());
redrawShape();
} catch (Throwable t) {
getPanel().getContext().handleThrowable(t);
}
}
protected Coordinate getModelSource() {
return modelSource;
}
protected Coordinate getModelDestination() {
return modelDestination;
}
protected void setModelSource(Coordinate source) {
this.modelSource = source;
}
protected void setViewSource(Point2D source) throws NoninvertibleTransformException {
setModelSource(getPanel().getViewport().toModelCoordinate(source));
}
protected void setViewDestination(Point2D destination) throws NoninvertibleTransformException {
setModelDestination(getPanel().getViewport().toModelCoordinate(destination));
}
protected void setModelDestination(Coordinate destination) {
this.modelDestination = snap(destination);
}
public void mouseReleased(MouseEvent e) {
try {
boolean dragComplete = isShapeOnScreen();
clearShape();
if (dragComplete) {
fireGestureFinished();
}
dragApproved = false;
} catch (Throwable t) {
getPanel().getContext().handleThrowable(t);
}
}
protected Shape getShape() throws Exception {
return getShape(getViewSource(), getViewDestination());
}
protected Point2D getViewSource() throws NoninvertibleTransformException {
return getPanel().getViewport().toViewPoint(getModelSource());
}
protected Point2D getViewDestination() throws NoninvertibleTransformException {
return getPanel().getViewport().toViewPoint(getModelDestination());
}
/**
*@return null if nothing should be drawn
*/
protected Shape getShape(Point2D source, Point2D destination)
throws Exception {
double minX = Math.min(source.getX(), destination.getX());
double minY = Math.min(source.getY(), destination.getY());
double maxX = Math.max(source.getX(), destination.getX());
double maxY = Math.max(source.getY(), destination.getY());
return new Rectangle.Double(minX, minY, maxX - minX, maxY - minY);
}
}