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.editing;
034:
035: import java.awt.Color;
036: import java.awt.Cursor;
037: import java.awt.Point;
038: import java.awt.Shape;
039: import java.awt.event.MouseEvent;
040: import java.awt.geom.Ellipse2D;
041: import java.awt.geom.NoninvertibleTransformException;
042: import java.awt.geom.Point2D;
043: import java.util.ArrayList;
044: import java.util.Collection;
045: import java.util.Iterator;
046:
047: import javax.swing.Icon;
048: import javax.swing.JComponent;
049:
050: import com.vividsolutions.jts.geom.Coordinate;
051: import com.vividsolutions.jts.geom.CoordinateFilter;
052: import com.vividsolutions.jts.geom.Envelope;
053: import com.vividsolutions.jts.geom.Geometry;
054: import com.vividsolutions.jump.I18N;
055: import com.vividsolutions.jump.workbench.model.Layer;
056: import com.vividsolutions.jump.workbench.plugin.EnableCheck;
057: import com.vividsolutions.jump.workbench.plugin.EnableCheckFactory;
058: import com.vividsolutions.jump.workbench.ui.EditTransaction;
059: import com.vividsolutions.jump.workbench.ui.cursortool.DragTool;
060: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
061:
062: public class MoveVertexTool extends DragTool {
063: public final static int TOLERANCE = 5;
064:
065: private EnableCheckFactory checkFactory;
066:
067: public MoveVertexTool(EnableCheckFactory checkFactory) {
068: this .checkFactory = checkFactory;
069: setColor(new Color(194, 179, 205));
070: setStrokeWidth(5);
071: allowSnapping();
072: }
073:
074: public Cursor getCursor() {
075: return createCursor(IconLoader.icon("MoveVertexCursor3.gif")
076: .getImage());
077: }
078:
079: public Icon getIcon() {
080: return IconLoader.icon("MoveVertex.gif");
081: }
082:
083: protected void gestureFinished() throws Exception {
084: reportNothingToUndoYet();
085:
086: //#execute(UndoableCommand) will be called. [Jon Aquino]
087: moveVertices(getModelSource(), getModelDestination());
088: }
089:
090: public void mousePressed(final MouseEvent e) {
091: try {
092: if (!check(checkFactory
093: .createAtLeastNLayersMustBeEditableCheck(1))) {
094: return;
095: }
096: if (!check(checkFactory
097: .createAtLeastNItemsMustBeSelectedCheck(1))) {
098: return;
099: }
100: if (!check(new EnableCheck() {
101: public String check(JComponent component) {
102: try {
103: return !nearSelectionHandle(e.getPoint()) ? I18N
104: .get("ui.cursortool.MoveVertexTool.no-editable-selection-handles-here")
105: : null;
106: } catch (Exception e) {
107: return e.toString();
108: }
109: }
110:
111: })) {
112: return;
113: }
114: super .mousePressed(e);
115: } catch (Throwable t) {
116: getPanel().getContext().handleThrowable(t);
117: }
118: }
119:
120: private boolean nearSelectionHandle(Point2D p)
121: throws NoninvertibleTransformException {
122: final Envelope buffer = vertexBuffer(getPanel().getViewport()
123: .toModelCoordinate(p));
124: final boolean[] result = new boolean[] { false };
125: for (Iterator i = getPanel().getSelectionManager()
126: .getLayersWithSelectedItems().iterator(); i.hasNext();) {
127: Layer layer = (Layer) i.next();
128: if (!layer.isEditable()) {
129: continue;
130: }
131: for (Iterator j = getPanel().getSelectionManager()
132: .getSelectedItems(layer).iterator(); j.hasNext();) {
133: Geometry item = (Geometry) j.next();
134: item.apply(new CoordinateFilter() {
135: public void filter(Coordinate coord) {
136: if (buffer.contains(coord)) {
137: result[0] = true;
138: }
139: }
140: });
141: }
142: }
143: return result[0];
144: }
145:
146: private Envelope vertexBuffer(Coordinate c)
147: throws NoninvertibleTransformException {
148: double tolerance = TOLERANCE
149: / getPanel().getViewport().getScale();
150: return vertexBuffer(c, tolerance);
151: }
152:
153: public void moveVertices(Coordinate initialLocation,
154: Coordinate finalLocation) throws Exception {
155: final Envelope oldVertexBuffer = vertexBuffer(initialLocation);
156: final Coordinate newVertex = finalLocation;
157: ArrayList transactions = new ArrayList();
158: for (Iterator i = getPanel().getSelectionManager()
159: .getLayersWithSelectedItems().iterator(); i.hasNext();) {
160: Layer layerWithSelectedItems = (Layer) i.next();
161: if (!layerWithSelectedItems.isEditable()) {
162: continue;
163: }
164: transactions.add(createTransaction(layerWithSelectedItems,
165: oldVertexBuffer, newVertex));
166: }
167: EditTransaction.commit(transactions);
168: }
169:
170: private EditTransaction createTransaction(Layer layer,
171: final Envelope oldVertexBuffer, final Coordinate newVertex) {
172: return EditTransaction.createTransactionOnSelection(
173: new EditTransaction.SelectionEditor() {
174: public Geometry edit(
175: Geometry geometryWithSelectedItems,
176: Collection selectedItems) {
177: for (Iterator j = selectedItems.iterator(); j
178: .hasNext();) {
179: Geometry item = (Geometry) j.next();
180: edit(item);
181: }
182: return geometryWithSelectedItems;
183: }
184:
185: private void edit(Geometry selectedItem) {
186: selectedItem.apply(new CoordinateFilter() {
187: public void filter(Coordinate coordinate) {
188: if (oldVertexBuffer
189: .contains(coordinate)) {
190: coordinate.x = newVertex.x;
191: coordinate.y = newVertex.y;
192: }
193: }
194: });
195: }
196: }, getPanel(), getPanel().getContext(), getName(),
197: layer, isRollingBackInvalidEdits(), false);
198: }
199:
200: protected Shape getShape(Point2D source, Point2D destination)
201: throws Exception {
202: double radius = 20;
203:
204: return new Ellipse2D.Double(destination.getX() - (radius / 2),
205: destination.getY() - (radius / 2), radius, radius);
206: }
207:
208: private Envelope vertexBuffer(Coordinate vertex, double tolerance) {
209: return new Envelope(vertex.x - tolerance, vertex.x + tolerance,
210: vertex.y - tolerance, vertex.y + tolerance);
211: }
212: }
|