source: josm/trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java@ 484

Last change on this file since 484 was 484, checked in by tabacha, 16 years ago

put some strings e.g. status bar messages in tr() to translate it

File size: 9.5 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions.mapmode;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Cursor;
7import java.awt.Point;
8import java.awt.Rectangle;
9import java.awt.event.KeyEvent;
10import java.awt.event.MouseEvent;
11import java.awt.event.ActionEvent;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.LinkedList;
15
16import javax.swing.JOptionPane;
17
18import org.openstreetmap.josm.Main;
19import org.openstreetmap.josm.actions.GroupAction;
20import org.openstreetmap.josm.command.Command;
21import org.openstreetmap.josm.command.MoveCommand;
22import org.openstreetmap.josm.command.RotateCommand;
23import org.openstreetmap.josm.data.coor.EastNorth;
24import org.openstreetmap.josm.data.osm.Node;
25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
27import org.openstreetmap.josm.gui.MapFrame;
28import org.openstreetmap.josm.gui.SelectionManager;
29import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
30import org.openstreetmap.josm.tools.ImageProvider;
31import org.openstreetmap.josm.actions.MergeNodesAction;
32/**
33 * Move is an action that can move all kind of OsmPrimitives (except Keys for now).
34 *
35 * If an selected object is under the mouse when dragging, move all selected objects.
36 * If an unselected object is under the mouse when dragging, it becomes selected
37 * and will be moved.
38 * If no object is under the mouse, move all selected objects (if any)
39 *
40 * @author imi
41 */
42public class SelectAction extends MapMode implements SelectionEnded {
43
44 enum Mode { move, rotate, select }
45 private Mode mode = null;
46 private long mouseDownTime = 0;
47 private boolean didMove = false;
48
49 /**
50 * The old cursor before the user pressed the mouse button.
51 */
52 private Cursor oldCursor;
53 /**
54 * The position of the mouse before the user moves a node.
55 */
56 private Point mousePos;
57 private SelectionManager selectionManager;
58
59 /**
60 * The time which needs to pass between click and release before something
61 * counts as a move
62 */
63 private int initialMoveDelay = 100;
64
65 /**
66 * Create a new SelectAction
67 * @param mapFrame The MapFrame this action belongs to.
68 */
69 public SelectAction(MapFrame mapFrame) {
70 super(tr("Select"), "move/move", tr("Select, move and rotate objects"),
71 KeyEvent.VK_S, mapFrame,
72 getCursor("normal", "selection", Cursor.DEFAULT_CURSOR));
73 putValue("help", "Action/Move/Move");
74 selectionManager = new SelectionManager(this, false, mapFrame.mapView);
75 try { initialMoveDelay = Integer.parseInt(Main.pref.get("edit.initial-move-delay","100")); } catch (NumberFormatException x) {};
76 }
77
78 private static Cursor getCursor(String name, String mod, int def) {
79 try {
80 return ImageProvider.getCursor(name, mod);
81 } catch (Exception e) {
82 }
83 return Cursor.getPredefinedCursor(def);
84 }
85
86 private static Cursor getCursor(String name, int def) {
87 return getCursor(name, null, def);
88 }
89
90 private void setCursor(Cursor c) {
91 if (oldCursor == null) {
92 oldCursor = Main.map.mapView.getCursor();
93 Main.map.mapView.setCursor(c);
94 }
95 }
96
97 private void restoreCursor() {
98 if (oldCursor != null) {
99 Main.map.mapView.setCursor(oldCursor);
100 oldCursor = null;
101 }
102 }
103
104 @Override public void enterMode() {
105 super.enterMode();
106 Main.map.mapView.addMouseListener(this);
107 Main.map.mapView.addMouseMotionListener(this);
108 }
109
110 @Override public void exitMode() {
111 super.exitMode();
112 Main.map.mapView.removeMouseListener(this);
113 Main.map.mapView.removeMouseMotionListener(this);
114 }
115
116 /**
117 * If the left mouse button is pressed, move all currently selected
118 * objects (if one of them is under the mouse) or the current one under the
119 * mouse (which will become selected).
120 */
121 @Override public void mouseDragged(MouseEvent e) {
122 if (mode == Mode.select) return;
123
124 // do not count anything as a move if it lasts less than 100 milliseconds.
125 if ((mode == Mode.move) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
126
127 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
128 return;
129
130 if (mode == Mode.move) {
131 setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
132 }
133
134 if (mousePos == null) {
135 mousePos = e.getPoint();
136 }
137
138 EastNorth mouseEN = Main.map.mapView.getEastNorth(e.getX(), e.getY());
139 EastNorth mouseStartEN = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y);
140 double dx = mouseEN.east() - mouseStartEN.east();
141 double dy = mouseEN.north() - mouseStartEN.north();
142 if (dx == 0 && dy == 0)
143 return;
144
145 Collection<OsmPrimitive> selection = Main.ds.getSelected();
146 Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
147
148 // when rotating, having only one node makes no sense - quit silently
149 if (mode == Mode.rotate && affectedNodes.size() < 2)
150 return;
151
152
153 // check if any coordinate would be outside the world
154 for (OsmPrimitive osm : affectedNodes) {
155 if (osm instanceof Node && ((Node)osm).coor.isOutSideWorld()) {
156 JOptionPane.showMessageDialog(Main.parent,
157 tr("Cannot move objects outside of the world."));
158 return;
159 }
160 }
161 Command c = !Main.main.undoRedo.commands.isEmpty()
162 ? Main.main.undoRedo.commands.getLast() : null;
163
164 if (mode == Mode.move) {
165 if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).objects))
166 ((MoveCommand)c).moveAgain(dx,dy);
167 else
168 Main.main.undoRedo.add(new MoveCommand(selection, dx, dy));
169 } else if (mode == Mode.rotate) {
170 if (c instanceof RotateCommand && affectedNodes.equals(((RotateCommand)c).objects))
171 ((RotateCommand)c).rotateAgain(mouseStartEN, mouseEN);
172 else
173 Main.main.undoRedo.add(new RotateCommand(selection, mouseStartEN, mouseEN));
174 }
175
176 Main.map.mapView.repaint();
177 mousePos = e.getPoint();
178
179 didMove = true;
180 }
181
182 /**
183 * Look, whether any object is selected. If not, select the nearest node.
184 * If there are no nodes in the dataset, do nothing.
185 *
186 * If the user did not press the left mouse button, do nothing.
187 *
188 * Also remember the starting position of the movement and change the mouse
189 * cursor to movement.
190 */
191 @Override public void mousePressed(MouseEvent e) {
192 if (e.getButton() != MouseEvent.BUTTON1)
193 return;
194 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
195 boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
196 boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
197
198 mouseDownTime = System.currentTimeMillis();
199 didMove = false;
200
201 Collection<OsmPrimitive> osmColl =
202 Main.map.mapView.getNearestCollection(e.getPoint());
203
204 if (ctrl && shift) {
205 if (Main.ds.getSelected().isEmpty()) selectPrims(osmColl, true, false);
206 mode = Mode.rotate;
207 setCursor(ImageProvider.getCursor("rotate", null));
208 } else if (!osmColl.isEmpty()) {
209 // Don't replace the selection now if the user clicked on a
210 // selected object (this would break moving of selected groups).
211 // We'll do that later in mouseReleased if the user didn't try to
212 // move.
213 selectPrims(osmColl,
214 shift || Main.ds.getSelected().containsAll(osmColl),
215 ctrl);
216 mode = Mode.move;
217 } else {
218 mode = Mode.select;
219 oldCursor = Main.map.mapView.getCursor();
220 selectionManager.register(Main.map.mapView);
221 selectionManager.mousePressed(e);
222 }
223
224 updateStatusLine();
225 Main.map.mapView.repaint();
226
227 mousePos = e.getPoint();
228 }
229
230 /**
231 * Restore the old mouse cursor.
232 */
233 @Override public void mouseReleased(MouseEvent e) {
234 if (mode == Mode.select) {
235 selectionManager.unregister(Main.map.mapView);
236 }
237 restoreCursor();
238
239 if (mode == Mode.move) {
240 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
241 boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
242 if (!didMove) {
243 selectPrims(
244 Main.map.mapView.getNearestCollection(e.getPoint()),
245 shift, ctrl);
246 } else if (ctrl) {
247 Collection<OsmPrimitive> selection = Main.ds.getSelected();
248 Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
249 Collection<Node> nn = Main.map.mapView.getNearestNodes(e.getPoint(), affectedNodes);
250 if (nn != null) {
251 Node n = nn.iterator().next();
252 LinkedList<Node> selNodes = new LinkedList<Node>();
253 for (OsmPrimitive osm : selection)
254 if (osm instanceof Node)
255 selNodes.add((Node)osm);
256 if (selNodes.size() > 0) {
257 selNodes.add(n);
258 MergeNodesAction.mergeNodes(selNodes, n);
259 }
260 }
261 }
262 }
263
264 updateStatusLine();
265 mode = null;
266 updateStatusLine();
267 }
268
269 public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
270 selectPrims(selectionManager.getObjectsInRectangle(r, alt), shift, ctrl);
271 }
272
273 public void selectPrims(Collection<OsmPrimitive> selectionList, boolean shift, boolean ctrl) {
274 if (shift && ctrl)
275 return; // not allowed together
276
277 Collection<OsmPrimitive> curSel;
278 if (!ctrl && !shift)
279 curSel = new LinkedList<OsmPrimitive>(); // new selection will replace the old.
280 else
281 curSel = Main.ds.getSelected();
282
283 for (OsmPrimitive osm : selectionList)
284 if (ctrl)
285 curSel.remove(osm);
286 else
287 curSel.add(osm);
288 Main.ds.setSelected(curSel);
289 Main.map.mapView.repaint();
290 }
291
292 @Override public String getModeHelpText() {
293 if (mode == Mode.select) {
294 return tr("Release the mouse button to select the objects in the rectangle.");
295 } else if (mode == Mode.move) {
296 return tr("Release the mouse button to stop moving. Ctrl to merge with nearest node.");
297 } else if (mode == Mode.rotate) {
298 return tr("Release the mouse button to stop rotating.");
299 } else {
300 return tr("Move objects by dragging; Shift to add to selection; Shift-Ctrl to rotate selected; or change selection");
301 }
302 }
303}
Note: See TracBrowser for help on using the repository browser.