source: osm/applications/editors/josm/plugins/FastDraw/src/org/openstreetmap/josm/plugins/fastdraw/FastDrawingMode.java

Last change on this file was 36057, checked in by taylor.smock, 14 months ago

Fix #21659: IAE: Listener FastDrawingMode was not registered before or already removed

This occurs because FastDraw tries to only be available when there is an unlocked
data layer.

Also clean up the code a bit (SonarLint, checkstyle).

File size: 25.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.fastdraw;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Cursor;
8import java.awt.Graphics2D;
9import java.awt.Point;
10import java.awt.event.KeyEvent;
11import java.awt.event.MouseEvent;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Iterator;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.Map;
19
20import javax.swing.JOptionPane;
21
22import org.openstreetmap.josm.actions.mapmode.MapMode;
23import org.openstreetmap.josm.command.AddCommand;
24import org.openstreetmap.josm.command.ChangeCommand;
25import org.openstreetmap.josm.command.Command;
26import org.openstreetmap.josm.command.DeleteCommand;
27import org.openstreetmap.josm.command.SequenceCommand;
28import org.openstreetmap.josm.data.Bounds;
29import org.openstreetmap.josm.data.UndoRedoHandler;
30import org.openstreetmap.josm.data.coor.LatLon;
31import org.openstreetmap.josm.data.osm.DataSet;
32import org.openstreetmap.josm.data.osm.Node;
33import org.openstreetmap.josm.data.osm.OsmPrimitive;
34import org.openstreetmap.josm.data.osm.Way;
35import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
36import org.openstreetmap.josm.gui.MainApplication;
37import org.openstreetmap.josm.gui.MapFrame;
38import org.openstreetmap.josm.gui.MapView;
39import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
40import org.openstreetmap.josm.gui.layer.Layer;
41import org.openstreetmap.josm.gui.layer.MapViewPaintable;
42import org.openstreetmap.josm.gui.util.KeyPressReleaseListener;
43import org.openstreetmap.josm.gui.util.ModifierExListener;
44import org.openstreetmap.josm.tools.ImageProvider;
45import org.openstreetmap.josm.tools.Shortcut;
46import org.openstreetmap.josm.tools.TextTagParser;
47
48/**
49 * Fast Drawing map mode.
50 */
51class FastDrawingMode extends MapMode implements MapViewPaintable, KeyPressReleaseListener, ModifierExListener {
52 private static final long serialVersionUID = -3395918050593965929L;
53 // CHECKSTYLE.OFF: LineLength
54 private static final String SIMPLIFY_MODE_MESSAGE =
55 tr("Q=Options, Enter=save, Ctrl-Enter=save with tags, Up/Down=tune");
56 private static final String DRAWING_MODE_MESSAGE =
57 tr("Click or Click&drag to continue, Ctrl-Click to add fixed node, Shift-Click to delete, Enter to simplify or save, Ctrl-Shift-Click to start new line");
58 // CHECKSTYLE.ON: LineLength
59
60 private FDSettings settings;
61
62 private final DrawnPolyLine line;
63 private MapView mv;
64 private String statusText;
65 private boolean drawing;
66 private double eps;
67 private final Cursor cursorDraw;
68 private final Cursor cursorCtrl;
69 private final Cursor cursorShift;
70 private final Cursor cursorReady;
71 private final Cursor cursorDrawing;
72 private boolean nearSomeNode;
73 private LatLon highlightedFragmentStart;
74 private int nearestPointIndex;
75 private int dragNode = -1;
76 private List<Node> oldNodes;
77
78 private boolean lineWasSaved;
79 private boolean deltaChanged;
80 private Way oldWay;
81
82 FastDrawingMode() {
83 super(tr("FastDrawing"), "turbopen", tr("Fast drawing mode"),
84 Shortcut.registerShortcut("mapmode:fastdraw", tr("Mode: {0}", tr("Fast drawing mode")), KeyEvent.VK_F, Shortcut.SHIFT),
85 Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
86 line = new DrawnPolyLine();
87 cursorDraw = ImageProvider.getCursor("crosshair", null);
88 cursorCtrl = ImageProvider.getCursor("crosshair", "fixed");
89 cursorShift = ImageProvider.getCursor("crosshair", "new");
90 cursorReady = ImageProvider.getCursor("crosshair", "ready");
91 cursorDrawing = ImageProvider.getCursor("crosshair", "mode");
92 }
93
94 // <editor-fold defaultstate="collapsed" desc="Event listeners">
95
96 @Override
97 public void enterMode() {
98 this.updateEnabledState();
99 if (!isEnabled())
100 return;
101 super.enterMode();
102 lineWasSaved = false;
103 settings = new FDSettings();
104 settings.loadPrefs();
105 settings.savePrefs();
106
107 MapFrame map = MainApplication.getMap();
108 eps = settings.startingEps;
109 mv = map.mapView;
110 line.setMv(mv);
111
112 if (getLayerManager().getEditDataSet() == null) return;
113
114 map.mapView.addMouseListener(this);
115 map.mapView.addMouseMotionListener(this);
116 map.mapView.addTemporaryLayer(this);
117
118 map.keyDetector.addKeyListener(this);
119 map.keyDetector.addModifierExListener(this);
120 }
121
122 @Override
123 public void exitMode() {
124 super.exitMode();
125 if (line.wasSimplified() && !lineWasSaved) saveAsWay(false);
126 MapFrame map = MainApplication.getMap();
127
128 map.mapView.removeMouseListener(this);
129 map.mapView.removeMouseMotionListener(this);
130
131 map.mapView.removeTemporaryLayer(this);
132
133 map.keyDetector.removeKeyListener(this);
134 map.keyDetector.removeModifierExListener(this);
135
136 settings.savePrefs();
137 map.mapView.setCursor(cursorDraw);
138 repaint();
139 }
140
141 @Override
142 public boolean layerIsSupported(Layer l) {
143 return isEditableDataLayer(l);
144 }
145
146 @Override
147 protected void updateEnabledState() {
148 setEnabled(getLayerManager().getEditLayer() != null);
149 }
150
151 private final ArrayList<Point> fixedPoints = new ArrayList<>(3000); // temporary storage for paint
152
153 ////////// Event listener methods
154 @Override
155 public void paint(Graphics2D g, MapView mv, Bounds bbox) {
156 LinkedList<LatLon> pts = line.getPoints();
157 if (pts.isEmpty()) return;
158
159 if (line.wasSimplified()) {
160 // we are drawing simplified version, that exists
161 g.setStroke(settings.simplifiedStroke);
162 } else {
163 g.setStroke(settings.normalStroke);
164 }
165
166 int bigDotSize = settings.bigDotSize;
167
168 Point p1, p2;
169 LatLon pp1, pp2;
170 p1 = line.getPoint(pts.get(0));
171 g.setColor(settings.COLOR_FIXED.get());
172 g.fillOval(p1.x - bigDotSize/2, p1.y - bigDotSize/2, bigDotSize, bigDotSize);
173 Color lineColor, initLineColor;
174 initLineColor = line.wasSimplified() ? settings.COLOR_SIMPLIFIED.get() : settings.COLOR_NORMAL.get();
175 lineColor = initLineColor;
176 int rp, dp;
177 dp = line.wasSimplified() ? settings.bigDotSize : settings.dotSize; rp = dp/2;
178 if (pts.size() > 1) {
179 Iterator<LatLon> it1, it2;
180 it1 = pts.listIterator(0);
181 it2 = pts.listIterator(1);
182 fixedPoints.clear();
183 for (int i = 0; i < pts.size() - 1; i++) {
184 pp1 = it1.next();
185 p1 = line.getPoint(pp1);
186 pp2 = it2.next();
187 p2 = line.getPoint(pp2);
188 if (shift && highlightedFragmentStart == pp1 && nearestPointIndex < 0) {
189 lineColor = settings.COLOR_SELECTEDFRAGMENT.get();
190 }
191 if (!shift && line.isLastPoint(i)) {
192 lineColor = settings.COLOR_EDITEDFRAGMENT.get();
193 }
194 g.setColor(lineColor);
195 g.drawLine(p1.x, p1.y, p2.x, p2.y);
196 if (line.isFixed(pp2)) {
197 lineColor = initLineColor;
198 fixedPoints.add(p2);
199 } else {
200 g.fillRect(p2.x - rp, p2.y - rp, dp, dp);
201 }
202 if (!drawing && !line.wasSimplified() && nearestPointIndex == i+1) {
203 if (shift) {
204 // highlight node to delete
205 g.setStroke(settings.deleteStroke);
206 g.setColor(settings.COLOR_DELETE.get());
207 g.drawLine(p2.x - 5, p2.y - 5, p2.x + 5, p2.y + 5);
208 g.drawLine(p2.x - 5, p2.y + 5, p2.x + 5, p2.y - 5);
209 g.setStroke(settings.normalStroke);
210 } else if (ctrl) {
211 // highlight node to toggle fixation
212 g.setStroke(settings.deleteStroke);
213 g.setColor(line.isFixed(pp2) ? settings.COLOR_NORMAL.get() : settings.COLOR_FIXED.get());
214 g.fillOval(p2.x - bigDotSize/2-2, p2.y - bigDotSize/2-2, bigDotSize+4, bigDotSize+4);
215 g.setStroke(settings.normalStroke);
216 }
217 }
218 }
219 g.setColor(settings.COLOR_FIXED.get());
220 for (Point p: fixedPoints) {
221 g.fillOval(p.x - bigDotSize/2, p.y - bigDotSize/2, bigDotSize, bigDotSize);
222 }
223 }
224 if (settings.drawLastSegment && !drawing && dragNode < 0 && !shift &&
225 nearestPointIndex <= 0 && !line.wasSimplified()) {
226 // draw line to current point
227 g.setColor(lineColor);
228 Point lp = line.getLastPoint();
229 Point mp = mv.getMousePosition();
230 if (lp != null && mp != null) g.drawLine(lp.x, lp.y, mp.x, mp.y);
231 }
232 if (deltaChanged) {
233 g.setColor(lineColor);
234 Point lp = line.getLastPoint();
235 int r = (int) settings.minPixelsBetweenPoints;
236 if (lp != null) g.drawOval(lp.x-r, lp.y-r, 2*r, 2*r);
237 }
238 }
239
240 @Override
241 public void mousePressed(MouseEvent e) {
242 if (!isEnabled()) return;
243 if (e.getButton() != MouseEvent.BUTTON1) return;
244 updateKeyModifiers(e);
245
246 requestFocusInMapView();
247
248 int idx = line.findClosestPoint(e.getPoint(), settings.maxDist);
249 if (idx == 0 && !line.isClosed()) {
250 line.closeLine();
251 // the way should become closed
252 drawing = false;
253 dragNode = 0;
254 updateCursor();
255 return;
256 }
257 autoCloseIfNeeded();
258
259 if (ctrl && shift) {
260 newDrawing();
261 repaint();
262 return;
263 }
264 if (!ctrl && shift) {
265 if (idx >= 0) {
266 line.deleteNode(idx);
267 nearestPointIndex = -1;
268 } else
269 line.tryToDeleteSegment(e.getPoint());
270 return;
271 }
272 if (idx >= 0) {
273 if (ctrl) {
274 // toggle fixed point
275 line.toggleFixed(idx);
276 }
277 // node dragging
278 dragNode = idx;
279 return;
280 }
281 startDrawing(e.getPoint(), settings.fixedClick);
282 }
283
284 private void startDrawing(Point point, boolean fixFlag) {
285 drawing = true;
286 if (line.wasSimplified()) {
287 // new line started after simplification
288 // we need to save old line
289 saveAsWay(false);
290 newDrawing();
291 }
292
293 LatLon p = mv.getLatLon(point.x, point.y);
294 if (settings.snapNodes) { // find existing node near point and use it
295 Node nd1 = getNearestNode(point, settings.maxDist);
296 if (nd1 != null) {
297 // found node, make it fixed point of the line
298 p = nd1.getCoor();
299 line.fixPoint(p);
300 }
301 }
302
303 line.addLast(p);
304 if (ctrl || fixFlag) line.fixPoint(p);
305
306 setStatusLine(tr("Please move the mouse to draw new way"));
307 repaint();
308 }
309
310 @Override
311 public void mouseReleased(MouseEvent e) {
312 if (e.getButton() != MouseEvent.BUTTON1) return;
313 stopDrawing();
314 }
315
316 private void stopDrawing() {
317 if (!isEnabled()) return;
318 dragNode = -1;
319 drawing = false;
320 highlightedFragmentStart = null;
321 if (!line.isClosed()) setStatusLine(DRAWING_MODE_MESSAGE);
322 updateCursor();
323 repaint();
324 }
325
326 @Override
327 public void mouseDragged(MouseEvent e) {
328 mouseMoved(e);
329 }
330
331 @Override
332 public void mouseMoved(MouseEvent e) {
333 if (!isEnabled()) return;
334 updateKeyModifiers(e);
335 deltaChanged = false;
336 Node nd1 = getNearestNode(e.getPoint(), settings.maxDist);
337 boolean nearSomeNode2 = nd1 != null;
338 boolean needRepaint = false;
339 if (nearSomeNode != nearSomeNode2) {
340 nearSomeNode = nearSomeNode2;
341 updateCursor();
342 needRepaint = true;
343 }
344
345 int nearestIdx2 = line.findClosestPoint(e.getPoint(), settings.maxDist);
346 if (nearestPointIndex != nearestIdx2) {
347 nearestPointIndex = nearestIdx2;
348 updateCursor();
349 needRepaint = true;
350 }
351 if (settings.drawLastSegment) {
352 needRepaint = true;
353 }
354
355 if (!drawing) {
356 if (dragNode >= 0 && dragNode < line.getPointCount()) {
357 line.moveNode(dragNode, getLatLon(e));
358 repaint();
359 return;
360 }
361
362 if (shift && nearestPointIndex == -1) {
363 // find line fragment to highlight
364 LatLon h2 = line.findBigSegment(e.getPoint());
365 if (highlightedFragmentStart != h2) {
366 highlightedFragmentStart = h2;
367 needRepaint = true;
368 }
369 }
370
371 if (needRepaint) {
372 repaint();
373 }
374 return;
375 }
376 if (line.isClosed()) setStatusLine(SIMPLIFY_MODE_MESSAGE);
377
378 // do not draw points close to existing points - we do not want self-intersections
379 if (nearestPointIndex >= 0) {
380 return;
381 }
382
383 Point lastP = line.getLastPoint(); // last point of line fragment being edited
384
385 // free mouse-drawing
386 if (nearSomeNode) {
387 if (nd1 != null && settings.snapNodes && lastP != null
388 && Math.hypot((double) e.getX() - lastP.x, (double) e.getY() - lastP.y) > 1e-2) {
389 line.addFixed(nd1.getCoor()); // snap to node coords
390 repaint();
391 return;
392 }
393 } else {
394 if (lastP != null && Math.hypot((double) e.getX() - lastP.x, (double) e.getY() - lastP.y) > settings.minPixelsBetweenPoints) {
395 line.addLast(getLatLon(e)); // add new point
396 repaint();
397 return;
398 }
399 }
400 autoCloseIfNeeded();
401 }
402
403 @Override
404 public void doKeyPressed(KeyEvent e) {
405 if (getShortcut().isEvent(e)) { // repeated press
406 tryToLoadWay();
407 return;
408 }
409 switch(e.getKeyCode()) {
410 case KeyEvent.VK_BACK_SPACE:
411 if (line.wasSimplified()) {
412 // return to line editing
413 line.clearSimplifiedVersion();
414 repaint();
415 eps = settings.startingEps;
416 }
417 back();
418 break;
419 case KeyEvent.VK_ENTER:
420 e.consume();
421 // first Enter = simplify, second = save the way
422 if (!line.wasSimplified()) {
423 switch(settings.simplifyMode) {
424 case 0: //case 1:
425 eps = line.autoSimplify(settings.startingEps, settings.epsilonMult,
426 settings.pkmBlockSize, settings.maxPointsPerKm);
427 break;
428 case 1: //case 2: case 3:
429 line.simplify(eps);
430 break;
431 }
432 if (settings.simplifyMode == 2) {
433 // autosave
434 saveAsWay(true);
435 } else {
436 repaint();
437 showSimplifyHint();
438 }
439 } else {
440 saveAsWay(true);
441 }
442 break;
443 case KeyEvent.VK_DOWN:
444 if (ctrl || shift || alt) return;
445 // more details
446 e.consume();
447 if (line.wasSimplified()) changeEpsilon(settings.epsilonMult);
448 else changeDelta(1/1.1);
449 break;
450 case KeyEvent.VK_UP:
451 if (ctrl || shift || alt) return;
452 // fewer details
453 e.consume();
454 if (line.wasSimplified()) changeEpsilon(1/settings.epsilonMult);
455 else changeDelta(1.1);
456 break;
457 case KeyEvent.VK_ESCAPE:
458 e.consume();
459 Point lastPoint = line.getLastPoint();
460 if (!line.isClosed()) line.moveToTheEnd();
461 if (lastPoint == null || lastPoint.equals(line.getLastPoint())) {
462 if (line.getPoints().size() > 5) {
463 boolean answer = ConditionalOptionPaneUtil.showConfirmationDialog(
464 "delete_drawn_line", MainApplication.getMainFrame(),
465 tr("Are you sure you do not want to save the line containing {0} points?",
466 line.getPoints().size()), tr("Delete confirmation"),
467 JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_OPTION);
468 if (!answer) break;
469 }
470 newDrawing(); // stop drawing
471 MainApplication.getMap().selectSelectTool(false);
472 }
473 break;
474
475 case KeyEvent.VK_I:
476 JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
477 tr("{0} m - length of the line\n{1} nodes\n{2} points per km (maximum)\n{3} points per km (average)",
478 line.getLength(), line.getPoints().size(), line.getNodesPerKm(settings.pkmBlockSize),
479 line.getNodesPerKm(1_000_000)),
480 tr("Line information"), JOptionPane.INFORMATION_MESSAGE);
481 break;
482 case KeyEvent.VK_Q:
483 // fewer details
484 e.consume();
485 new FastDrawConfigDialog(settings).showDialog();
486 if (line.wasSimplified()) {
487 eps = line.autoSimplify(settings.startingEps, settings.epsilonMult, settings.pkmBlockSize, settings.maxPointsPerKm);
488 showSimplifyHint();
489 }
490 repaint();
491 break;
492 case KeyEvent.VK_SPACE:
493 e.consume();
494 if (!drawing) {
495 Point p = MainApplication.getMap().mapView.getMousePosition();
496 if (p != null) startDrawing(p, settings.fixedSpacebar);
497 }
498 break;
499 }
500 }
501
502 @Override
503 public void doKeyReleased(KeyEvent keyEvent) {
504 if (keyEvent.getKeyCode() == KeyEvent.VK_SPACE) stopDrawing();
505 updateCursor();
506 }
507
508 @Override
509 public void modifiersExChanged(int modifiers) {
510 updateKeyModifiersEx(modifiers);
511 updateCursor();
512 }
513
514 @Override
515 protected void updateStatusLine() {
516 MainApplication.getMap().statusLine.setHelpText(statusText);
517 MainApplication.getMap().statusLine.repaint();
518 }
519 // </editor-fold>
520
521 // <editor-fold defaultstate="collapsed" desc="Different action helper methods">
522 public void newDrawing() {
523 oldWay = null; oldNodes = null;
524 eps = settings.startingEps;
525 line.clear();
526 }
527
528 private void saveAsWay(boolean autoExit) {
529 List<LatLon> pts = line.getPoints();
530 int n = pts.size();
531 if (n < 2) return; //do not save oversimplified lines
532 if (line.isClosed() && n == 2) return;
533 if (line.isClosed() && n == 3) pts.remove(2); // two-point way can not be closed
534
535 DataSet ds = getLayerManager().getEditDataSet();
536 if (ds == null) return;
537 Collection<Command> cmds = new LinkedList<>();
538 int i = 0;
539
540 Way w;
541 if (oldWay == null) {
542 w = new Way();
543 } else {
544 w = new Way(oldWay);
545 w.setNodes(new ArrayList<>()); // nodes will be created from scratch
546 }
547
548 LatLon first = pts.get(0);
549 Node firstNode = null;
550
551 for (LatLon p : pts) {
552 Node nd = MainApplication.getMap().mapView.getNearestNode(line.getPoint(p), OsmPrimitive::isSelectable);
553 // there may be a node with the same coords!
554
555 if (nd != null && p.greatCircleDistance(nd) > 0.01) nd = null;
556 if (nd == null) {
557 if (i > 0 && p.equals(first)) {
558 nd = firstNode;
559 } else {
560 nd = new Node(p);
561 cmds.add(new AddCommand(ds, nd));
562 }
563 }
564 if (nd.isOutSideWorld()) {
565 JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
566 tr("Cannot place node outside of the world."));
567 return;
568 }
569 if (i == 0) {
570 firstNode = nd;
571 }
572 w.addNode(nd);
573 i++;
574 }
575 if (ctrl) {
576 // paste tags - from ctrl-shift-v
577 new OsmTransferHandler().pasteTags(Collections.singleton(w));
578 }
579 if (!settings.autoTags.isEmpty()) {
580 Map<String, String> tags = TextTagParser.readTagsFromText(settings.autoTags);
581 for (Map.Entry<String, String> entry : tags.entrySet()) {
582 w.put(entry.getKey(), entry.getValue());
583 }
584 }
585 if (oldWay != null) {
586 List<Node> nodes = w.getNodes();
587 cmds.add(new ChangeCommand(oldWay, w));
588 for (Node nd: oldNodes) {
589 // node from old way but not in new way
590 if (!nodes.contains(nd)) {
591 List<OsmPrimitive> refs = nd.getReferrers();
592 // does someone need this node? if no-delete it.
593 if (refs.size() == 1 && !nd.isDeleted() && nd.isUsable() && !nd.isTagged()) cmds.add(new DeleteCommand(nd));
594 }
595 }
596 oldWay = null; // that is all with this command
597 } else cmds.add(new AddCommand(ds, w));
598 Command c = new SequenceCommand(tr("Draw the way by mouse"), cmds);
599 UndoRedoHandler.getInstance().add(c);
600 lineWasSaved = true;
601 newDrawing(); // stop drawing
602 if (autoExit) {
603 // Select this way and switch drawing mode off
604 ds.setSelected(w);
605 MainApplication.getMap().selectSelectTool(false);
606 }
607 }
608
609 public void back() {
610 line.undo();
611 repaint();
612 }
613
614 void changeEpsilon(double k) {
615 eps *= k;
616 line.simplify(eps);
617 /* I18N: Eps = Epsilon, the tolerance parameter */
618 showSimplifyHint();
619 repaint();
620 }
621
622 void changeDelta(double k) {
623 settings.minPixelsBetweenPoints *= k;
624 deltaChanged = true;
625
626 setStatusLine(tr("min distance={0} px ({1} m)", (int) settings.minPixelsBetweenPoints,
627 mv.getDist100Pixel()/100*settings.minPixelsBetweenPoints));
628 repaint();
629 }
630
631 private void loadFromWay(Way w) {
632
633 Object[] nodes = w.getNodes().toArray();
634 int n = nodes.length;
635 if (w.isClosed()) n--;
636 for (int i = 0; i < n; i++) {
637 Node nd = (Node) nodes[i];
638 List<OsmPrimitive> refs = nd.getReferrers();
639 if (refs.size() > 1 || nd.isTagged()) {
640 line.addFixed(nd.getCoor());
641 } else {
642 line.addLast(nd.getCoor());
643 }
644 }
645 if (w.isClosed()) line.closeLine();
646 oldNodes = w.getNodes();
647 oldWay = w;
648 }
649
650 private void setStatusLine(String tr) {
651 statusText = tr;
652 updateStatusLine();
653 }
654
655 private void showSimplifyHint() {
656 setStatusLine(tr("Eps={0}, {1} points, {2} p/km",
657 eps, line.getSimplePointsCount(), line.getNodesPerKm(settings.pkmBlockSize))+" "
658 + SIMPLIFY_MODE_MESSAGE);
659 }
660
661 private void updateCursor() {
662 MapView mapView = MainApplication.getMap().mapView;
663 if (shift) mapView.setCursor(cursorShift); else
664 if (line.isClosed() || (nearestPointIndex == 0)) mapView.setCursor(cursorReady);
665 else if (ctrl) mapView.setCursor(cursorCtrl);
666 else if (nearSomeNode && settings.snapNodes) mapView.setCursor(cursorCtrl);
667 else if (drawing) mapView.setCursor(cursorDrawing);
668 else mapView.setCursor(cursorDraw);
669 }
670
671 private static void repaint() {
672 MainApplication.getMap().mapView.repaint();
673 }
674
675 private void tryToLoadWay() {
676 updateCursor();
677 Collection<Way> selectedWays = MainApplication.getLayerManager().getEditDataSet().getSelectedWays();
678 if (selectedWays != null // if there is a selection
679 && selectedWays.size() == 1 // and one way is selected
680 && line.getPoints().isEmpty()) /* and there is no already drawn line */ {
681 // we can start drawing new way starting from old one
682 Way w = selectedWays.iterator().next();
683
684 if (w.isNew() || settings.allowEditExistingWays) loadFromWay(w);
685 }
686 }
687
688 private void autoCloseIfNeeded() {
689 if (settings.drawClosed && line.getPointCount() > 1 && !line.isClosed()) {
690 line.closeLine();
691 }
692 }
693 // </editor-fold>
694
695 // <editor-fold defaultstate="collapsed" desc="Helper functions">
696
697 private Node getNearestNode(Point point, double maxDist) {
698 Node nd = MainApplication.getMap().mapView.getNearestNode(point, OsmPrimitive::isSelectable);
699 if (nd != null && line.getPoint(nd.getCoor()).distance(point) <= maxDist) return nd;
700 else return null;
701 }
702
703 LatLon getLatLon(MouseEvent e) {
704 return mv.getLatLon(e.getX(), e.getY());
705 }
706 // </editor-fold>
707}
Note: See TracBrowser for help on using the repository browser.