/*
* MoverTool.java
*
* Created on April 20, 2005, 7:14 PM
*/
package ika.map.tools;
import ika.geo.*;
import ika.utils.FocusUtils;
import ika.gui.MapComponent;
import java.awt.geom.*;
import java.awt.event.*;
/**
* MoverTool - a tool to move GeoObjects by dragging them with the mouse, or
* moving them with an arrow key.
* @author Bernhard Jenny, Institute of Cartography, ETH Zurich.
*/
public class MoverTool extends SelectionEditingTool implements CombinableTool {
/**
* The number of pixels by which selected objects are moved when an
* arrow key is pressed.
*/
final double KEY_MOVE_DIST = 3;
/**
* The number of pixels by which selected objects are moved when an
* arrow key is pressed and the shift key is down.
*/
final double KEY_SHIFT_MOVE_DIST = 15;
/**
* if selectOnDragStart is true, GeoObjects that are not selected are
* selected when a click on them is detected and if this click is followed
* by a dragging action.
*/
private boolean selectOnDragStart = false;
/**
* Create a new instance.
* @param mapComponent The MapComponent for which this MapTool provides its services.
*/
public MoverTool(MapComponent mapComponent) {
super(mapComponent);
}
/**
* The mouse started a drag, while this MapTool was the active one.
* @param point The location of the mouse in world coordinates.
* @param evt The original event.
*/
public void startDrag(Point2D.Double point, MouseEvent evt) {
// search if mouse started drag by a mouse down event on a GeoObject
GeoObject geoObject = mapComponent.getObjectAtPosition(point,
SelectionTool.CLICK_PIXEL_TOLERANCE, true, true);
if (geoObject == null) {
// no object found under cursor
this.startPoint = null;
return;
}
if (this.selectOnDragStart
&& !geoObject.isSelected()
&& geoObject.isSelectable()) {
// We received a click on an unselected item followed by dragging.
mapComponent.selectByPoint(point, false, SelectionTool.CLICK_PIXEL_TOLERANCE);
}
// remember the start position of the drag
this.startPoint = (Point2D.Double)point.clone();
this.captureBackground();
}
/**
* A drag ends, while this MapTool was the active one.
* @param point The location of the mouse in world coordinates.
* @param evt The original event.
*/
public void endDrag(Point2D.Double point, MouseEvent evt) {
if (this.startPoint == null)
return;
try {
// Test whether the objects were altered during the dragging.
if (!this.isDragging() || !this.differentFromStartPoint(point))
return;
// compute the moving distance
final double dx = point.getX() - this.startPoint.getX();
final double dy = point.getY() - this.startPoint.getY();
final boolean moved = evt.isAltDown() ?
mapComponent.cloneAndMoveSelectedGeoObjects(dx, dy)
: mapComponent.moveSelectedGeoObjects(dx, dy);
if (this.differentFromStartPoint(point))
this.mapComponent.addUndo("Move");
} finally {
this.release();
}
}
/**
* Treat arrow key events.
* The event can be consumed (return true) or be delegated to other
* listeners (return false).
* @param keyEvent The new key event.
* @return True if the key event has been consumed, false otherwise.
*/
public boolean keyEvent(KeyEvent keyEvent) {
// give parent class a chance to treat escape key strokes
if (super.keyEvent(keyEvent))
return true;
// don't test for KEY_RELEASED. A series of arrow key events should move
// the selected objects continuosly.
// before computing anything, find out if an arrow key was pressed
double dx = 0;
double dy = 0;
switch (keyEvent.getKeyCode()) {
case KeyEvent.VK_UP:
dy = 1;
break;
case KeyEvent.VK_DOWN:
dy = -1;
break;
case KeyEvent.VK_LEFT:
dx = -1;
break;
case KeyEvent.VK_RIGHT:
dx = 1;
break;
}
if (dx == 0 && dy == 0)
return false;
// make sure the parent window of the mapComponent owns the focus.
if (!FocusUtils.parentWindowHasFocus(this.mapComponent))
return false;
// make sure the component with the current focus does not react
// on arrow key strokes.
if (FocusUtils.currentFocusOwnerListensForKey(keyEvent.getKeyCode()))
return false;
// no other component is handling arrow key strokes,
// it is save to move the currently selected objects.
final double scale = this.mapComponent.getScaleFactor();
final double d;
if (keyEvent.isShiftDown())
d = KEY_SHIFT_MOVE_DIST / scale;
else
d = KEY_MOVE_DIST / scale;
dx *= d;
dy *= d;
final boolean moved = keyEvent.isAltDown() ?
mapComponent.cloneAndMoveSelectedGeoObjects(dx, dy)
: mapComponent.moveSelectedGeoObjects(dx, dy);
this.mapComponent.addUndo("Move");
// inform MapToolActionListeners about action
if (moved)
;//this.informMapToolActionListeners("Move"); !!! ???
return moved;
}
protected String getCursorName() {
return "movearrow";
}
/**
* Returns whether the tool is currently dragging an object.
*/
public boolean isDragging() {
return this.startPoint != null;
}
public boolean isSelectOnDragStart() {
return selectOnDragStart;
}
public void setSelectOnDragStart(boolean selectOnDragStart) {
this.selectOnDragStart = selectOnDragStart;
}
protected AffineTransform computeTransform(Point2D.Double point, MouseEvent evt) {
final double dx = point.getX() - startPoint.getX();
final double dy = point.getY() - startPoint.getY();
return AffineTransform.getTranslateInstance(dx, dy);
}
public boolean adjustCursor(Point2D.Double point) {
return false;
}
}