001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.workbench.ui.cursortool;
034:
035: import java.awt.Rectangle;
036: import java.awt.Shape;
037: import java.awt.event.MouseEvent;
038: import java.awt.geom.NoninvertibleTransformException;
039: import java.awt.geom.Point2D;
040:
041: import com.vividsolutions.jts.geom.Coordinate;
042: import com.vividsolutions.jts.geom.Envelope;
043:
044: /**
045: * The default implementation draws a selection box, but this can be overridden
046: * (even to draw nothing).
047: */
048: public abstract class DragTool extends AbstractCursorTool {
049: public static final int DEFAULT_VIEW_CLICK_BUFFER = 2;
050: private int viewClickBuffer = DEFAULT_VIEW_CLICK_BUFFER;
051: /** Modify using #setSource */
052: protected Coordinate modelSource = null;
053: /** Modify using #setDestination */
054: protected Coordinate modelDestination = null;
055: private boolean dragApproved = false;
056:
057: /**
058: * Begins handling of the drag. Subclasses can prevent handling of the drag
059: * by overriding this method and not calling it.
060: */
061: public void mousePressed(MouseEvent e) {
062: super .mousePressed(e);
063: dragApproved = true;
064: try {
065: setViewSource(e.getPoint());
066: } catch (NoninvertibleTransformException x) {
067: getPanel().getContext().handleThrowable(x);
068: }
069: //Probably doesn't make sense to snap the source. Note that MoveSelectedItem's
070: //override of #snap assumes that it is only used on the destination. [Jon Aquino]
071: }
072:
073: /**
074: * A click is converted into a box by being expanded by this amount in the
075: * four directions.
076: */
077: protected void setViewClickBuffer(int clickBuffer) {
078: this .viewClickBuffer = clickBuffer;
079: }
080:
081: protected boolean wasClick() {
082: return getModelSource().equals(getModelDestination());
083: }
084:
085: protected Envelope getBoxInModelCoordinates()
086: throws NoninvertibleTransformException {
087: double minX = Math.min(getModelSource().x,
088: getModelDestination().x);
089: double maxX = Math.max(getModelSource().x,
090: getModelDestination().x);
091: double minY = Math.min(getModelSource().y,
092: getModelDestination().y);
093: double maxY = Math.max(getModelSource().y,
094: getModelDestination().y);
095:
096: if (wasClick()) {
097: minX -= modelClickBuffer();
098: maxX += modelClickBuffer();
099: minY -= modelClickBuffer();
100: maxY += modelClickBuffer();
101: }
102:
103: return new Envelope(minX, maxX, minY, maxY);
104: }
105:
106: protected double modelClickBuffer() {
107: return viewClickBuffer / getPanel().getViewport().getScale();
108: }
109:
110: public void mouseDragged(MouseEvent e) {
111: try {
112: if (!dragApproved) {
113: //dragApproved will be false if:
114: // -- the drag began outside the panel
115: // -- a subclass wanted to prevent handling of the drag by overriding
116: // #mousePressed and not calling it; for example, EditDelineationTool.
117: //[Jon Aquino]
118: return;
119: }
120:
121: setViewDestination(e.getPoint());
122: redrawShape();
123: } catch (Throwable t) {
124: getPanel().getContext().handleThrowable(t);
125: }
126: }
127:
128: protected Coordinate getModelSource() {
129: return modelSource;
130: }
131:
132: protected Coordinate getModelDestination() {
133: return modelDestination;
134: }
135:
136: protected void setModelSource(Coordinate source) {
137: this .modelSource = source;
138: }
139:
140: protected void setViewSource(Point2D source)
141: throws NoninvertibleTransformException {
142: setModelSource(getPanel().getViewport().toModelCoordinate(
143: source));
144: }
145:
146: protected void setViewDestination(Point2D destination)
147: throws NoninvertibleTransformException {
148: setModelDestination(getPanel().getViewport().toModelCoordinate(
149: destination));
150: }
151:
152: protected void setModelDestination(Coordinate destination) {
153: this .modelDestination = snap(destination);
154: }
155:
156: public void mouseReleased(MouseEvent e) {
157: try {
158: boolean dragComplete = isShapeOnScreen();
159: clearShape();
160:
161: if (dragComplete) {
162: fireGestureFinished();
163: }
164:
165: dragApproved = false;
166: } catch (Throwable t) {
167: getPanel().getContext().handleThrowable(t);
168: }
169: }
170:
171: protected Shape getShape() throws Exception {
172: return getShape(getViewSource(), getViewDestination());
173: }
174:
175: protected Point2D getViewSource()
176: throws NoninvertibleTransformException {
177: return getPanel().getViewport().toViewPoint(getModelSource());
178: }
179:
180: protected Point2D getViewDestination()
181: throws NoninvertibleTransformException {
182: return getPanel().getViewport().toViewPoint(
183: getModelDestination());
184: }
185:
186: /**
187: *@return null if nothing should be drawn
188: */
189: protected Shape getShape(Point2D source, Point2D destination)
190: throws Exception {
191: double minX = Math.min(source.getX(), destination.getX());
192: double minY = Math.min(source.getY(), destination.getY());
193: double maxX = Math.max(source.getX(), destination.getX());
194: double maxY = Math.max(source.getY(), destination.getY());
195:
196: return new Rectangle.Double(minX, minY, maxX - minX, maxY
197: - minY);
198: }
199:
200: }
|