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: * JUMP is Copyright (C) 2003 Vivid Solutions
006: *
007: * This program implements extensions to JUMP and is
008: * Copyright (C) 2004 Integrated Systems Analysts, Inc.
009: *
010: * This program is free software; you can redistribute it and/or
011: * modify it under the terms of the GNU General Public License
012: * as published by the Free Software Foundation; either version 2
013: * of the License, or (at your option) any later version.
014: *
015: * This program is distributed in the hope that it will be useful,
016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
018: * GNU General Public License for more details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with this program; if not, write to the Free Software
022: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
023: *
024: * For more information, contact:
025: *
026: * Integrated Systems Analysts, Inc.
027: * 630C Anchors St., Suite 101
028: * Fort Walton Beach, Florida
029: * USA
030: *
031: * (850)862-7321
032: */
033:
034: package org.openjump.core.ui.plugin.edittoolbox.cursortools;
035:
036: import java.awt.Rectangle;
037: import java.awt.Shape;
038: import java.awt.event.MouseEvent;
039: import java.awt.geom.NoninvertibleTransformException;
040: import java.awt.geom.Point2D;
041: import java.text.DecimalFormat;
042: import java.util.ArrayList;
043: import java.util.Collections;
044: import java.util.List;
045:
046: import org.openjump.core.ui.plugin.edittoolbox.tab.ConstraintManager;
047:
048: import com.vividsolutions.jts.geom.Coordinate;
049: import com.vividsolutions.jts.geom.Envelope;
050: import com.vividsolutions.jump.I18N;
051: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
052: import com.vividsolutions.jump.workbench.ui.cursortool.AbstractCursorTool;
053:
054: /**
055: * The default implementation draws a selection box, but this can be overridden
056: * (even to draw nothing).
057: */
058: public abstract class ConstrainedDragTool extends AbstractCursorTool {
059:
060: final static String lengthST = I18N
061: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.length");
062: final static String angleST = I18N
063: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.angle");
064: final static String degrees = I18N
065: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.degrees");
066:
067: public static final int DEFAULT_VIEW_CLICK_BUFFER = 2;
068: private int viewClickBuffer = DEFAULT_VIEW_CLICK_BUFFER;
069: /** Modify using #setSource */
070: protected Coordinate modelSource = null;
071: /** Modify using #setDestination */
072: protected Coordinate modelDestination = null;
073: private boolean dragApproved = false;
074:
075: protected List coordinates = new ArrayList();
076: private Coordinate tentativeCoordinate;
077: private ConstraintManager constraintManager;
078:
079: /**
080: * Begins handling of the drag. Subclasses can prevent handling of the drag
081: * by overriding this method and not calling it.
082: */
083: public void mousePressed(MouseEvent e) {
084: super .mousePressed(e);
085: dragApproved = true;
086: try {
087: setViewSource(e.getPoint());
088: } catch (NoninvertibleTransformException x) {
089: getPanel().getContext().handleThrowable(x);
090: }
091: //Probably doesn't make sense to snap the source. Note that MoveSelectedItem's
092: //override of #snap assumes that it is only used on the destination. [Jon Aquino]
093: }
094:
095: /**
096: * A click is converted into a box by being expanded by this amount in the
097: * four directions.
098: */
099: protected void setViewClickBuffer(int clickBuffer) {
100: this .viewClickBuffer = clickBuffer;
101: }
102:
103: protected boolean wasClick() {
104: return getModelSource().equals(getModelDestination());
105: }
106:
107: protected Envelope getBoxInModelCoordinates()
108: throws NoninvertibleTransformException {
109: double minX = Math.min(getModelSource().x,
110: getModelDestination().x);
111: double maxX = Math.max(getModelSource().x,
112: getModelDestination().x);
113: double minY = Math.min(getModelSource().y,
114: getModelDestination().y);
115: double maxY = Math.max(getModelSource().y,
116: getModelDestination().y);
117:
118: if (wasClick()) {
119: minX -= modelClickBuffer();
120: maxX += modelClickBuffer();
121: minY -= modelClickBuffer();
122: maxY += modelClickBuffer();
123: }
124:
125: return new Envelope(minX, maxX, minY, maxY);
126: }
127:
128: protected double modelClickBuffer() {
129: return viewClickBuffer / getPanel().getViewport().getScale();
130: }
131:
132: public void mouseDragged(MouseEvent e) {
133: try {
134: if (!dragApproved) {
135: //dragApproved will be false if:
136: // -- the drag began outside the panel
137: // -- a subclass wanted to prevent handling of the drag by overriding
138: // #mousePressed and not calling it; for example, EditDelineationTool.
139: //[Jon Aquino]
140: return;
141: }
142:
143: mouseLocationChanged(e);
144: redrawShape();
145: } catch (Throwable t) {
146: getPanel().getContext().handleThrowable(t);
147: }
148: }
149:
150: protected Coordinate doConstraint(MouseEvent e)
151: throws NoninvertibleTransformException {
152: Coordinate retPt = snap(e.getPoint());
153: retPt = constraintManager.constrain(getPanel(),
154: getCoordinates(), retPt, e);
155: return retPt;
156: }
157:
158: public List getCoordinates() {
159: return Collections.unmodifiableList(coordinates);
160: }
161:
162: protected void mouseLocationChanged(MouseEvent e) {
163: try {
164: tentativeCoordinate = doConstraint(e);
165: this .modelDestination = (Coordinate) tentativeCoordinate
166: .clone();
167: if (coordinates.isEmpty())
168: return;
169: Coordinate startPt = (Coordinate) coordinates
170: .get(coordinates.size() - 1);
171: double length = startPt.distance(tentativeCoordinate);
172: double angle = constraintManager.getBearing(startPt,
173: tentativeCoordinate);
174: DecimalFormat df2 = new DecimalFormat("##0.0#");
175: DecimalFormat df3 = new DecimalFormat("###,###,##0.0##");
176: getPanel().getContext().setStatusMessage(
177: lengthST + ": " + df3.format(length) + "; "
178: + angleST + ": " + df2.format(angle) + " "
179: + degrees);
180: // double length = Math.round(startPt.distance(tentativeCoordinate) * 1000.0) / 1000.0;
181: // double angle = Math.round(constraintManager.getBearing(startPt, tentativeCoordinate) * 100.0) / 100.0;
182: // getPanel().getContext().setStatusMessage(" length = " + length + "; angle = " + angle + " degrees");
183: } catch (Throwable t) {
184: getPanel().getContext().handleThrowable(t);
185: }
186: }
187:
188: protected Coordinate getModelSource() {
189: return modelSource;
190: }
191:
192: protected Coordinate getModelDestination() {
193: return modelDestination;
194: }
195:
196: protected void setModelSource(Coordinate source) {
197: this .modelSource = source;
198: }
199:
200: protected void setViewSource(Point2D source)
201: throws NoninvertibleTransformException {
202: setModelSource(getPanel().getViewport().toModelCoordinate(
203: source));
204: }
205:
206: // protected void setViewDestination(Point2D destination) throws NoninvertibleTransformException {
207: // setModelDestination(getPanel().getViewport().toModelCoordinate(destination));
208: // }
209: //
210: // protected void setModelDestination(Coordinate destination) {
211: // this.modelDestination = snap(destination);
212: // }
213:
214: public void mouseReleased(MouseEvent e) {
215: try {
216: boolean dragComplete = isShapeOnScreen();
217: clearShape();
218:
219: if (dragComplete) {
220: fireGestureFinished();
221: }
222:
223: dragApproved = false;
224: } catch (Throwable t) {
225: getPanel().getContext().handleThrowable(t);
226: }
227: }
228:
229: protected Shape getShape() throws Exception {
230: return getShape(getViewSource(), getViewDestination());
231: }
232:
233: protected Point2D getViewSource()
234: throws NoninvertibleTransformException {
235: return getPanel().getViewport().toViewPoint(getModelSource());
236: }
237:
238: protected Point2D getViewDestination()
239: throws NoninvertibleTransformException {
240: return getPanel().getViewport().toViewPoint(
241: getModelDestination());
242: }
243:
244: /**
245: *@return null if nothing should be drawn
246: */
247: protected Shape getShape(Point2D source, Point2D destination)
248: throws Exception {
249: double minX = Math.min(source.getX(), destination.getX());
250: double minY = Math.min(source.getY(), destination.getY());
251: double maxX = Math.max(source.getX(), destination.getX());
252: double maxY = Math.max(source.getY(), destination.getY());
253:
254: return new Rectangle.Double(minX, minY, maxX - minX, maxY
255: - minY);
256: }
257:
258: public void activate(LayerViewPanel layerViewPanel) {
259: super .activate(layerViewPanel);
260: constraintManager = new ConstraintManager(getWorkbench()
261: .getContext());
262: }
263: }
|