source: osm/applications/editors/josm/plugins/splinex/src/org/openstreetmap/josm/plugins/Splinex/DrawSplineAction.java

Last change on this file was 35936, checked in by taylor.smock, 2 years ago

fix #21770: Update deprecated functions in splinex

This replaces usages of LatLon#isOutsideWorld with Node#isOutsideWorld

File size: 17.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.Splinex;
3
4import static org.openstreetmap.josm.plugins.Splinex.SplinexPlugin.EPSILON;
5import static org.openstreetmap.josm.tools.I18n.marktr;
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.Color;
9import java.awt.Cursor;
10import java.awt.Graphics2D;
11import java.awt.Point;
12import java.awt.event.ActionEvent;
13import java.awt.event.KeyEvent;
14import java.awt.event.MouseEvent;
15import java.util.Collection;
16import java.util.HashMap;
17import java.util.Map;
18
19import javax.swing.AbstractAction;
20
21import org.openstreetmap.josm.actions.mapmode.MapMode;
22import org.openstreetmap.josm.command.Command;
23import org.openstreetmap.josm.command.MoveCommand;
24import org.openstreetmap.josm.data.Bounds;
25import org.openstreetmap.josm.data.UndoRedoHandler;
26import org.openstreetmap.josm.data.coor.EastNorth;
27import org.openstreetmap.josm.data.osm.Node;
28import org.openstreetmap.josm.data.osm.OsmPrimitive;
29import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
30import org.openstreetmap.josm.data.preferences.NamedColorProperty;
31import org.openstreetmap.josm.gui.MainApplication;
32import org.openstreetmap.josm.gui.MapFrame;
33import org.openstreetmap.josm.gui.MapView;
34import org.openstreetmap.josm.gui.layer.Layer;
35import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
36import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
37import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
38import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
39import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
40import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
41import org.openstreetmap.josm.gui.layer.MapViewPaintable;
42import org.openstreetmap.josm.gui.layer.OsmDataLayer;
43import org.openstreetmap.josm.gui.util.KeyPressReleaseListener;
44import org.openstreetmap.josm.gui.util.ModifierExListener;
45import org.openstreetmap.josm.plugins.Splinex.Spline.PointHandle;
46import org.openstreetmap.josm.plugins.Splinex.Spline.SplinePoint;
47import org.openstreetmap.josm.spi.preferences.Config;
48import org.openstreetmap.josm.tools.ImageProvider;
49import org.openstreetmap.josm.tools.Logging;
50import org.openstreetmap.josm.tools.Shortcut;
51
52@SuppressWarnings("serial")
53public class DrawSplineAction extends MapMode implements MapViewPaintable, KeyPressReleaseListener, ModifierExListener,
54 LayerChangeListener, ActiveLayerChangeListener {
55 private final Cursor cursorJoinNode;
56 private final Cursor cursorJoinWay;
57
58 private Color rubberLineColor;
59
60 private final Shortcut backspaceShortcut;
61 private final BackSpaceAction backspaceAction;
62
63 boolean drawHelperLine;
64
65 public DrawSplineAction(MapFrame mapFrame) {
66 super(tr("Spline drawing"), // name
67 "spline2", // icon name
68 tr("Draw a spline curve"), // tooltip
69 Shortcut.registerShortcut("mapmode:spline",
70 tr("Mode: {0}", tr("Spline drawing")),
71 KeyEvent.VK_L, Shortcut.DIRECT),
72 getCursor());
73
74 backspaceShortcut = Shortcut.registerShortcut("mapmode:backspace", tr("Backspace in Add mode"),
75 KeyEvent.VK_BACK_SPACE, Shortcut.DIRECT);
76 backspaceAction = new BackSpaceAction();
77 cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
78 cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway");
79 MainApplication.getLayerManager().addLayerChangeListener(this);
80 MainApplication.getLayerManager().addActiveLayerChangeListener(this);
81 readPreferences();
82 }
83
84 private static Cursor getCursor() {
85 try {
86 return ImageProvider.getCursor("crosshair", "spline");
87 } catch (Exception e) {
88 Logging.error(e);
89 }
90 return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
91 }
92
93 @Override
94 public void enterMode() {
95 if (!isEnabled())
96 return;
97 super.enterMode();
98
99 MainApplication.registerActionShortcut(backspaceAction, backspaceShortcut);
100
101 MapFrame map = MainApplication.getMap();
102 map.mapView.addMouseListener(this);
103 map.mapView.addMouseMotionListener(this);
104 map.mapView.addTemporaryLayer(this);
105
106 map.keyDetector.addModifierExListener(this);
107 map.keyDetector.addKeyListener(this);
108 }
109
110 int initialMoveDelay, initialMoveThreshold;
111
112 @Override
113 protected void readPreferences() {
114 rubberLineColor = new NamedColorProperty(marktr("helper line"), Color.RED).get();
115 initialMoveDelay = Config.getPref().getInt("edit.initial-move-", 200);
116 initialMoveThreshold = Config.getPref().getInt("edit.initial-move-threshold", 5);
117 initialMoveThreshold *= initialMoveThreshold;
118 drawHelperLine = Config.getPref().getBoolean("draw.helper-line", true);
119 }
120
121 @Override
122 public void exitMode() {
123 super.exitMode();
124 MapFrame map = MainApplication.getMap();
125 map.mapView.removeMouseListener(this);
126 map.mapView.removeMouseMotionListener(this);
127 map.mapView.removeTemporaryLayer(this);
128 MainApplication.unregisterActionShortcut(backspaceAction, backspaceShortcut);
129
130 map.statusLine.activateAnglePanel(false);
131 map.keyDetector.removeModifierExListener(this);
132 map.keyDetector.removeKeyListener(this);
133 removeHighlighting();
134 map.mapView.repaint();
135 }
136
137 @Override
138 public void modifiersExChanged(int modifiers) {
139 updateKeyModifiersEx(modifiers);
140 }
141
142 private Long mouseDownTime;
143 private PointHandle ph;
144 private Point helperEndpoint;
145 private Point clickPos;
146 public int index = 0;
147 boolean lockCounterpart;
148 private MoveCommand mc;
149 private boolean dragControl;
150 private boolean dragSpline;
151
152 @Override
153 public void mousePressed(MouseEvent e) {
154 mouseDownTime = null;
155 updateKeyModifiers(e);
156 if (e.getButton() != MouseEvent.BUTTON1) {
157 helperEndpoint = null; // Hide helper line when panning
158 return;
159 }
160 if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return;
161 Spline spl = getSpline();
162 if (spl == null) return;
163 helperEndpoint = null;
164 dragControl = false;
165 dragSpline = false;
166 mouseDownTime = System.currentTimeMillis();
167 ph = spl.getNearestPoint(MainApplication.getMap().mapView, e.getPoint());
168 if (e.getClickCount() == 2) {
169 if (!spl.isClosed() && spl.nodeCount() > 1 && ph != null && ph.point == SplinePoint.ENDPOINT
170 && ((ph.idx == 0 && direction == 1) || (ph.idx == spl.nodeCount() - 1 && direction == -1))) {
171 UndoRedoHandler.getInstance().add(spl.new CloseSplineCommand());
172 return;
173 }
174 spl.finishSpline();
175 MainApplication.getMap().repaint();
176 return;
177 }
178 clickPos = e.getPoint();
179 if (ph != null) {
180 if (ctrl) {
181 if (ph.point == SplinePoint.ENDPOINT) {
182 ph = ph.otherPoint(SplinePoint.CONTROL_NEXT);
183 lockCounterpart = true;
184 } else
185 lockCounterpart = false;
186 } else {
187 lockCounterpart = (ph.point != SplinePoint.ENDPOINT
188 && Math.abs(ph.sn.cprev.east() + ph.sn.cnext.east()) < EPSILON && Math.abs(ph.sn.cprev.north()
189 + ph.sn.cnext.north()) < EPSILON);
190 }
191 if (ph.point == SplinePoint.ENDPOINT && UndoRedoHandler.getInstance().hasUndoCommands()) {
192 Command cmd = UndoRedoHandler.getInstance().getLastCommand();
193 if (cmd instanceof MoveCommand) {
194 mc = (MoveCommand) cmd;
195 Collection<Node> pp = mc.getParticipatingPrimitives();
196 if (pp.size() != 1 || !pp.contains(ph.sn.node))
197 mc = null;
198 else
199 mc.changeStartPoint(ph.sn.node.getEastNorth());
200 }
201 }
202 if (ph.point != SplinePoint.ENDPOINT && UndoRedoHandler.getInstance().hasUndoCommands()) {
203 Command cmd = UndoRedoHandler.getInstance().getLastCommand();
204 if (!(cmd instanceof Spline.EditSplineCommand && ((Spline.EditSplineCommand) cmd).sn == ph.sn))
205 dragControl = true;
206 }
207 return;
208 }
209 if (!ctrl && spl.doesHit(e.getX(), e.getY(), MainApplication.getMap().mapView)) {
210 dragSpline = true;
211 return;
212 }
213 if (spl.isClosed()) return;
214 if (direction == 0) {
215 if (spl.nodeCount() < 2) {
216 direction = 1;
217 } else {
218 return;
219 }
220 }
221 Node n = null;
222 boolean existing = false;
223 if (!ctrl) {
224 n = MainApplication.getMap().mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable);
225 existing = true;
226 }
227 if (n == null) {
228 n = new Node(MainApplication.getMap().mapView.getLatLon(e.getX(), e.getY()));
229 existing = false;
230 }
231 int idx = direction == -1 ? 0 : spl.nodeCount();
232 UndoRedoHandler.getInstance().add(spl.new AddSplineNodeCommand(new Spline.SNode(n), existing, idx));
233 ph = spl.new PointHandle(idx, direction == -1 ? SplinePoint.CONTROL_PREV : SplinePoint.CONTROL_NEXT);
234 lockCounterpart = true;
235 MainApplication.getMap().repaint();
236 }
237
238 @Override
239 public void mouseReleased(MouseEvent e) {
240 mc = null;
241 mouseDownTime = null;
242 dragSpline = false;
243 clickPos = null;
244 mouseMoved(e);
245 if (direction == 0 && ph != null) {
246 if (ph.idx >= ph.getSpline().nodeCount() - 1)
247 direction = 1;
248 else if (ph.idx == 0)
249 direction = -1;
250 }
251 }
252
253 @Override
254 public void mouseDragged(MouseEvent e) {
255 updateKeyModifiers(e);
256 if (mouseDownTime == null) return;
257 if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return;
258 if (System.currentTimeMillis() - mouseDownTime < initialMoveDelay) return;
259 Spline spl = getSpline();
260 if (spl == null) return;
261 if (spl.isEmpty()) return;
262 if (clickPos != null && clickPos.distanceSq(e.getPoint()) < initialMoveThreshold)
263 return;
264 EastNorth en = MainApplication.getMap().mapView.getEastNorth(e.getX(), e.getY());
265 if (new Node(en).isOutSideWorld())
266 return;
267 if (dragSpline) {
268 if (mc == null) {
269 mc = new MoveCommand(spl.getNodes(), MainApplication.getMap().mapView.getEastNorth(clickPos.x, clickPos.y), en);
270 UndoRedoHandler.getInstance().add(mc);
271 clickPos = null;
272 } else
273 mc.applyVectorTo(en);
274 MainApplication.getMap().repaint();
275 return;
276 }
277 clickPos = null;
278 if (ph == null) return;
279 if (ph.point == SplinePoint.ENDPOINT) {
280 if (mc == null) {
281 mc = new MoveCommand(ph.sn.node, ph.sn.node.getEastNorth(), en);
282 UndoRedoHandler.getInstance().add(mc);
283 } else
284 mc.applyVectorTo(en);
285 } else {
286 if (dragControl) {
287 UndoRedoHandler.getInstance().add(new Spline.EditSplineCommand(ph.sn));
288 dragControl = false;
289 }
290 ph.movePoint(en);
291 if (lockCounterpart) {
292 if (ph.point == SplinePoint.CONTROL_NEXT)
293 ph.sn.cprev = new EastNorth(0, 0).subtract(ph.sn.cnext);
294 else if (ph.point == SplinePoint.CONTROL_PREV)
295 ph.sn.cnext = new EastNorth(0, 0).subtract(ph.sn.cprev);
296 }
297 }
298 MainApplication.getMap().repaint();
299 }
300
301 Node nodeHighlight;
302 short direction;
303
304 @Override
305 public void mouseMoved(MouseEvent e) {
306 updateKeyModifiers(e);
307 if (!MainApplication.getMap().mapView.isActiveLayerDrawable()) return;
308 Spline spl = getSpline();
309 if (spl == null) return;
310 Point oldHelperEndpoint = helperEndpoint;
311 PointHandle oldph = ph;
312 boolean redraw = false;
313 ph = spl.getNearestPoint(MainApplication.getMap().mapView, e.getPoint());
314 if (ph == null)
315 if (!ctrl && spl.doesHit(e.getX(), e.getY(), MainApplication.getMap().mapView)) {
316 helperEndpoint = null;
317 MainApplication.getMap().mapView.setNewCursor(Cursor.MOVE_CURSOR, this);
318 } else {
319 Node n = null;
320 if (!ctrl)
321 n = MainApplication.getMap().mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable);
322 if (n == null) {
323 redraw = removeHighlighting();
324 helperEndpoint = e.getPoint();
325 MainApplication.getMap().mapView.setNewCursor(cursor, this);
326 } else {
327 redraw = setHighlight(n);
328 MainApplication.getMap().mapView.setNewCursor(cursorJoinNode, this);
329 helperEndpoint = MainApplication.getMap().mapView.getPoint(n);
330 }
331 }
332 else {
333 helperEndpoint = null;
334 MainApplication.getMap().mapView.setNewCursor(cursorJoinWay, this);
335 if (ph.point == SplinePoint.ENDPOINT)
336 redraw = setHighlight(ph.sn.node);
337 else
338 redraw = removeHighlighting();
339 }
340 if (!drawHelperLine || spl.isClosed() || direction == 0)
341 helperEndpoint = null;
342
343 if (redraw || oldHelperEndpoint != helperEndpoint || (oldph == null && ph != null)
344 || (oldph != null && !oldph.equals(ph)))
345 MainApplication.getMap().repaint();
346 }
347
348 /**
349 * Repaint on mouse exit so that the helper line goes away.
350 */
351 @Override
352 public void mouseExited(MouseEvent e) {
353 if (!MainApplication.getMap().mapView.isActiveLayerDrawable())
354 return;
355 removeHighlighting();
356 helperEndpoint = null;
357 MainApplication.getMap().mapView.repaint();
358 }
359
360 private boolean setHighlight(Node n) {
361 if (nodeHighlight == n)
362 return false;
363 removeHighlighting();
364 nodeHighlight = n;
365 n.setHighlighted(true);
366 return true;
367 }
368
369 /**
370 * Removes target highlighting from primitives. Issues repaint if required.
371 * Returns true if a repaint has been issued.
372 */
373 private boolean removeHighlighting() {
374 if (nodeHighlight != null) {
375 nodeHighlight.setHighlighted(false);
376 nodeHighlight = null;
377 return true;
378 }
379 return false;
380 }
381
382 @Override
383 public void paint(Graphics2D g, MapView mv, Bounds box) {
384 Spline spl = getSpline();
385 if (spl == null)
386 return;
387 spl.paint(g, mv, rubberLineColor, Color.green, helperEndpoint, direction);
388 if (ph != null && (ph.point != SplinePoint.ENDPOINT || (nodeHighlight != null && nodeHighlight.isDeleted()))) {
389 g.setColor(MapPaintSettings.INSTANCE.getSelectedColor());
390 Point p = mv.getPoint(ph.getPoint());
391 g.fillRect(p.x - 1, p.y - 1, 3, 3);
392 }
393 }
394
395 @Override
396 public boolean layerIsSupported(Layer l) {
397 return isEditableDataLayer(l);
398 }
399
400 @Override
401 protected void updateEnabledState() {
402 setEnabled(getLayerManager().getEditLayer() != null);
403 }
404
405 public static class BackSpaceAction extends AbstractAction {
406 @Override
407 public void actionPerformed(ActionEvent e) {
408 UndoRedoHandler.getInstance().undo();
409 }
410 }
411
412 private Spline splCached;
413
414 Spline getSpline() {
415 if (splCached != null)
416 return splCached;
417 Layer l = getLayerManager().getEditLayer();
418 if (!(l instanceof OsmDataLayer))
419 return null;
420 splCached = layerSplines.get(l);
421 if (splCached == null)
422 splCached = new Spline();
423 layerSplines.put(l, splCached);
424 return splCached;
425 }
426
427 @Override
428 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
429 splCached = layerSplines.get(MainApplication.getLayerManager().getActiveLayer());
430 }
431
432 Map<Layer, Spline> layerSplines = new HashMap<>();
433
434 @Override
435 public void layerOrderChanged(LayerOrderChangeEvent e) {
436 // Do nothing
437 }
438
439 @Override
440 public void layerAdded(LayerAddEvent e) {
441 // Do nothing
442 }
443
444 @Override
445 public void layerRemoving(LayerRemoveEvent e) {
446 layerSplines.remove(e.getRemovedLayer());
447 splCached = null;
448 }
449
450 @Override
451 public void doKeyPressed(KeyEvent e) {
452 if (e.getKeyCode() == KeyEvent.VK_DELETE && ph != null) {
453 Spline spl = ph.getSpline();
454 if (spl.nodeCount() == 3 && spl.isClosed() && ph.idx == 1)
455 return; // Don't allow to delete node when it results with two-node closed spline
456 UndoRedoHandler.getInstance().add(spl.new DeleteSplineNodeCommand(ph.idx));
457 e.consume();
458 }
459 if (e.getKeyCode() == KeyEvent.VK_ESCAPE && direction != 0) {
460 direction = 0;
461 MainApplication.getMap().mapView.repaint();
462 e.consume();
463 }
464 }
465
466 @Override
467 public void doKeyReleased(KeyEvent e) {
468 // Do nothing
469 }
470}
Note: See TracBrowser for help on using the repository browser.