001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.tools.edit.behaviour;
016:
017: import java.util.HashMap;
018: import java.util.Map;
019: import java.util.Set;
020: import java.util.Map.Entry;
021:
022: import net.refractions.udig.core.IProvider;
023: import net.refractions.udig.project.command.UndoableComposite;
024: import net.refractions.udig.project.command.UndoableMapCommand;
025: import net.refractions.udig.project.ui.AnimationUpdater;
026: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseEvent;
027: import net.refractions.udig.tool.edit.internal.Messages;
028: import net.refractions.udig.tools.edit.EditPlugin;
029: import net.refractions.udig.tools.edit.EditState;
030: import net.refractions.udig.tools.edit.EditToolHandler;
031: import net.refractions.udig.tools.edit.EventBehaviour;
032: import net.refractions.udig.tools.edit.EventType;
033: import net.refractions.udig.tools.edit.LockingBehaviour;
034: import net.refractions.udig.tools.edit.animation.MessageBubble;
035: import net.refractions.udig.tools.edit.commands.DrawSnapAreaCommand;
036: import net.refractions.udig.tools.edit.commands.SetEditStateCommand;
037: import net.refractions.udig.tools.edit.commands.SnapToVertexCommand;
038: import net.refractions.udig.tools.edit.preferences.PreferenceUtil;
039: import net.refractions.udig.tools.edit.support.EditBlackboard;
040: import net.refractions.udig.tools.edit.support.EditGeom;
041: import net.refractions.udig.tools.edit.support.Point;
042: import net.refractions.udig.tools.edit.support.Selection;
043: import net.refractions.udig.tools.edit.support.SnapBehaviour;
044: import net.refractions.udig.tools.edit.validator.LegalShapeValidator;
045:
046: /**
047: * Mode that moves Vertices
048: * <p>
049: * Requirements:
050: * <ul>
051: * <li>currentGeom!=null;</li>
052: * <li>currentState is MODIFIED or NONE </li>
053: * <li>eventType is DRAGGED</li>
054: * <li>no modifiers</li>
055: * <li>{@link net.refractions.udig.tools.edit.MouseTracker#getDragStarted()} is over selected
056: * vertex (if not all vertices are selected)</li>
057: * <li>If all vertices are selected then
058: * {@link net.refractions.udig.tools.edit.MouseTracker#getDragStarted()} must be within the
059: * geometry.
060: * </ul>
061: * </p>
062: * <p>
063: * Action:
064: * <ul>
065: * <li>move the vertices selected by {@link VertexSelectorBehaviour} to location in
066: * {@link net.refractions.udig.project.ui.render.displayAdapter.MapMouseEvent}</li>
067: * <li>Locks the EditTool handler until mouse is released so other behaviours won't interfere</li>
068: * </ul>
069: * </p>
070: *
071: * @author Jesse
072: * @since 1.1.0
073: */
074: public class MoveVertexBehaviour implements EventBehaviour,
075: LockingBehaviour {
076:
077: PositionTracker tracker;
078:
079: public boolean isValid(EditToolHandler handler, MapMouseEvent e,
080: EventType eventType) {
081: boolean isLegalState = handler.getCurrentState() == EditState.MODIFYING
082: || handler.getCurrentState() == EditState.NONE
083: || handler.getCurrentState() == EditState.MOVING;
084: boolean isEventDragged = eventType == EventType.DRAGGED;
085: boolean noModifiersDown = !e.modifiersDown();
086: boolean button1IsDown = (e.buttons ^ MapMouseEvent.BUTTON1) == 0;
087: boolean currentGeomNotNull = handler.getCurrentGeom() != null;
088:
089: return isLegalState
090: && isEventDragged
091: && noModifiersDown
092: && button1IsDown
093: && currentGeomNotNull
094: && (handler.isLockOwner(this ) || startedOverSelectedVertex(handler));
095: }
096:
097: private boolean startedOverSelectedVertex(EditToolHandler handler) {
098: // if tracker!=null then the move has started so the selection is no longer
099: // at the same spot as the selected point so return true
100: if (tracker != null)
101: return true;
102: Point started = handler.getMouseTracker().getDragStarted();
103: EditBlackboard editBlackboard = handler
104: .getEditBlackboard(handler.getEditLayer());
105: Point point = handler.getEditBlackboard(handler.getEditLayer())
106: .overVertex(
107: Point.valueOf(started.getX(), started.getY()),
108: PreferenceUtil.instance().getVertexRadius());
109: if (point == null) {
110: point = Point.valueOf(started.getX(), started.getY());
111: }
112: return getPointsToMove(handler, editBlackboard).contains(point);
113: }
114:
115: DrawSnapAreaCommand drawSnapArea;
116:
117: public UndoableMapCommand getCommand(EditToolHandler handler,
118: MapMouseEvent e, EventType eventType) {
119: if (handler.getCurrentState() != EditState.MOVING)
120: handler.setCurrentState(EditState.MOVING);
121:
122: if (!isValid(handler, e, eventType))
123: throw new IllegalArgumentException(
124: "Not valid state", new Exception()); //$NON-NLS-1$
125:
126: EditBlackboard editBlackboard2 = handler
127: .getEditBlackboard(handler.getEditLayer());
128: editBlackboard2.startBatchingEvents();
129: try {
130: if (tracker == null) {
131: handler.lock(this );
132: Point closestPoint = editBlackboard2.overVertex(Point
133: .valueOf(e.x, e.y), PreferenceUtil.instance()
134: .getVertexRadius(), false);
135: Map<EditGeom, Boolean> changedStatus = new HashMap<EditGeom, Boolean>();
136: for (EditGeom geom : editBlackboard2.getGeoms()) {
137: changedStatus.put(geom, geom.isChanged());
138: }
139: tracker = new PositionTracker(closestPoint, handler
140: .getMouseTracker().getDragStarted(),
141: getPointsToMove(handler, editBlackboard2),
142: changedStatus);
143: handler.getBehaviours().add(tracker);
144: if (isSnappingValid()
145: && PreferenceUtil.instance().getSnapBehaviour() != SnapBehaviour.GRID) {
146: drawSnapArea = new DrawSnapAreaCommand(tracker);
147: handler.getContext().getViewportPane()
148: .addDrawCommand(drawSnapArea);
149:
150: }
151: }
152:
153: if (tracker.lastPoint == null) {
154: tracker.lastPoint = handler.getMouseTracker()
155: .getDragStarted();
156: }
157:
158: Point point = Point.valueOf(e.x, e.y);
159:
160: int deltaX = point.getX() - tracker.lastPoint.getX(), deltaY = point
161: .getY()
162: - tracker.lastPoint.getY();
163:
164: doMove(deltaX, deltaY, handler, editBlackboard2,
165: tracker.selection);
166:
167: tracker.lastPoint = point;
168: return null;
169: } finally {
170: editBlackboard2.fireBatchedEvents();
171: handler.repaint();
172: }
173: }
174:
175: protected void doMove(int deltaX, int deltaY,
176: EditToolHandler handler, EditBlackboard editBlackboard2,
177: Selection selectionToMove) {
178: editBlackboard2.moveSelection(deltaX, deltaY, selectionToMove);
179: }
180:
181: /**
182: * Returns true if snapping should be used.
183: *
184: * @return
185: */
186: protected boolean isSnappingValid() {
187: return PreferenceUtil.instance().getSnapBehaviour() != SnapBehaviour.OFF;
188: }
189:
190: /**
191: * Returns the points that will be moved.
192: *
193: * @param handler
194: * @return the points that will be moved.
195: */
196: protected Selection getPointsToMove(EditToolHandler handler,
197: EditBlackboard blackboard) {
198: return blackboard.getSelection();
199: }
200:
201: public void handleError(EditToolHandler handler, Throwable error,
202: UndoableMapCommand command) {
203: EditPlugin.log("", error); //$NON-NLS-1$
204: }
205:
206: public class PositionTracker implements LockingBehaviour,
207: IProvider<Point> {
208: Point lastPoint;
209: private Point start;
210: private Selection selection;
211: private Map<EditGeom, Boolean> dirtyStatesBeforeMove;
212:
213: public PositionTracker(Point closestPoint, Point dragStarted,
214: Selection selection,
215: Map<EditGeom, Boolean> dirtyStatesBeforeMove) {
216: this .selection = selection;
217: lastPoint = closestPoint != null ? closestPoint
218: : dragStarted;
219: this .start = lastPoint;
220: this .dirtyStatesBeforeMove = dirtyStatesBeforeMove;
221:
222: }
223:
224: public boolean isValid(EditToolHandler handler,
225: MapMouseEvent e, EventType eventType) {
226: return eventType == EventType.RELEASED;
227: }
228:
229: public UndoableMapCommand getCommand(EditToolHandler handler,
230: MapMouseEvent e, EventType eventType) {
231:
232: if (drawSnapArea != null) {
233: drawSnapArea.setValid(false);
234: drawSnapArea = null;
235: }
236: handler.getBehaviours().remove(this );
237: tracker = null;
238: handler.unlock(this );
239:
240: LegalShapeValidator validator = new LegalShapeValidator();
241: String errorMessage = validator.isValid(handler, e,
242: eventType);
243: if (errorMessage == null) {
244: UndoableComposite command = new UndoableComposite();
245: command.getCommands()
246: .add(
247: new SnapToVertexCommand(lastPoint,
248: this .selection, handler, start,
249: EditState.MODIFYING,
250: isSnappingValid()));
251: command.getFinalizerCommands().add(
252: new SetEditStateCommand(handler,
253: EditState.MODIFYING));
254: return command;
255: } else {
256: MessageBubble bubble = new MessageBubble(
257: e.getPoint().x, e.getPoint().y,
258: Messages.MoveVertexBehaviour_validationError
259: + "\n" + errorMessage, //$NON-NLS-1$
260: PreferenceUtil.instance()
261: .getMessageDisplayDelay());
262: AnimationUpdater.runTimer(handler.getContext()
263: .getMapDisplay(), bubble);
264: EditBlackboard editBlackboard = handler
265: .getEditBlackboard(handler.getEditLayer());
266: doMove(start.getX() - lastPoint.getX(), start.getY()
267: - lastPoint.getY(), handler, editBlackboard,
268: selection);
269: Set<Entry<EditGeom, Boolean>> entries = dirtyStatesBeforeMove
270: .entrySet();
271: for (Entry<EditGeom, Boolean> entry : entries) {
272: entry.getKey().setChanged(entry.getValue());
273: }
274: return null;
275: }
276:
277: }
278:
279: public void handleError(EditToolHandler handler,
280: Throwable error, UndoableMapCommand command) {
281: EditPlugin.log("", error); //$NON-NLS-1$
282: }
283:
284: public Point get() {
285: return lastPoint;
286: }
287:
288: public Object getKey(EditToolHandler handler) {
289: return MoveVertexBehaviour.this ;
290: }
291:
292: }
293:
294: public Object getKey(EditToolHandler handler) {
295: return this;
296: }
297:
298: }
|