/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * JUMP is Copyright (C) 2003 Vivid Solutions * * This program implements extensions to JUMP and is * Copyright (C) 2004 Integrated Systems Analysts, Inc. * * 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: * * Integrated Systems Analysts, Inc. * 630C Anchors St., Suite 101 * Fort Walton Beach, Florida * USA * * (850)862-7321 */ package org.openjump.core.ui.plugin.edittoolbox.cursortools; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.MouseEvent; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.openjump.core.ui.plugin.edittoolbox.tab.ConstraintManager; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jump.I18N; import com.vividsolutions.jump.workbench.ui.LayerViewPanel; import com.vividsolutions.jump.workbench.ui.cursortool.AbstractCursorTool; /** * The default implementation draws a selection box, but this can be overridden * (even to draw nothing). */ public abstract class ConstrainedDragTool extends AbstractCursorTool { final static String lengthST =I18N.get("org.openjump.core.ui.plugin.edittoolbox.cursortools.length"); final static String angleST =I18N.get("org.openjump.core.ui.plugin.edittoolbox.cursortools.angle"); final static String degrees =I18N.get("org.openjump.core.ui.plugin.edittoolbox.cursortools.degrees"); 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; protected List coordinates = new ArrayList(); private Coordinate tentativeCoordinate; private ConstraintManager constraintManager; /** * 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; } mouseLocationChanged(e); redrawShape(); } catch (Throwable t) { getPanel().getContext().handleThrowable(t); } } protected Coordinate doConstraint(MouseEvent e) throws NoninvertibleTransformException { Coordinate retPt = snap(e.getPoint()); retPt = constraintManager.constrain(getPanel(), getCoordinates(), retPt, e); return retPt; } public List getCoordinates() { return Collections.unmodifiableList(coordinates); } protected void mouseLocationChanged(MouseEvent e) { try { tentativeCoordinate = doConstraint(e); this.modelDestination = (Coordinate)tentativeCoordinate.clone(); if (coordinates.isEmpty()) return; Coordinate startPt = (Coordinate)coordinates.get(coordinates.size() - 1); double length = startPt.distance(tentativeCoordinate); double angle = constraintManager.getBearing(startPt, tentativeCoordinate); DecimalFormat df2 = new DecimalFormat("##0.0#"); DecimalFormat df3 = new DecimalFormat("###,###,##0.0##"); getPanel().getContext().setStatusMessage(lengthST + ": " + df3.format(length) + "; " + angleST + ": " + df2.format(angle) + " " + degrees); // double length = Math.round(startPt.distance(tentativeCoordinate) * 1000.0) / 1000.0; // double angle = Math.round(constraintManager.getBearing(startPt, tentativeCoordinate) * 100.0) / 100.0; // getPanel().getContext().setStatusMessage(" length = " + length + "; angle = " + angle + " degrees"); } 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); } public void activate(LayerViewPanel layerViewPanel) { super.activate(layerViewPanel); constraintManager = new ConstraintManager(getWorkbench().getContext()); } }