source: josm/trunk/src/org/openstreetmap/josm/actions/ImageryAdjustAction.java@ 16770

Last change on this file since 16770 was 15733, checked in by simon04, 4 years ago

see #17220 - LayerListDialog: show imagery offset in tooltip

  • Property svn:eol-style set to native
File size: 13.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.AWTEvent;
7import java.awt.Cursor;
8import java.awt.GridBagLayout;
9import java.awt.Insets;
10import java.awt.Toolkit;
11import java.awt.event.AWTEventListener;
12import java.awt.event.ActionEvent;
13import java.awt.event.FocusEvent;
14import java.awt.event.FocusListener;
15import java.awt.event.KeyEvent;
16import java.awt.event.MouseEvent;
17import java.util.Locale;
18
19import javax.swing.JLabel;
20import javax.swing.JPanel;
21
22import org.openstreetmap.josm.actions.mapmode.MapMode;
23import org.openstreetmap.josm.data.coor.EastNorth;
24import org.openstreetmap.josm.data.coor.LatLon;
25import org.openstreetmap.josm.data.imagery.OffsetBookmark;
26import org.openstreetmap.josm.data.projection.ProjectionRegistry;
27import org.openstreetmap.josm.gui.ExtendedDialog;
28import org.openstreetmap.josm.gui.MainApplication;
29import org.openstreetmap.josm.gui.MapFrame;
30import org.openstreetmap.josm.gui.MapView;
31import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
32import org.openstreetmap.josm.gui.util.WindowGeometry;
33import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
34import org.openstreetmap.josm.gui.widgets.JosmTextField;
35import org.openstreetmap.josm.tools.GBC;
36import org.openstreetmap.josm.tools.ImageProvider;
37import org.openstreetmap.josm.tools.JosmDecimalFormatSymbolsProvider;
38import org.openstreetmap.josm.tools.Logging;
39
40/**
41 * Adjust the position of an imagery layer.
42 * @since 3715
43 */
44public class ImageryAdjustAction extends MapMode implements AWTEventListener {
45 private static ImageryOffsetDialog offsetDialog;
46
47 private transient OffsetBookmark old;
48 private transient OffsetBookmark tempOffset;
49 private EastNorth prevEastNorth;
50 private transient AbstractTileSourceLayer<?> layer;
51 private MapMode oldMapMode;
52 private boolean exitingMode;
53 private boolean restoreOldMode;
54
55 /**
56 * Constructs a new {@code ImageryAdjustAction} for the given layer.
57 * @param layer The imagery layer
58 */
59 public ImageryAdjustAction(AbstractTileSourceLayer<?> layer) {
60 super(tr("New offset"), "adjustimg", tr("Adjust the position of this imagery layer"),
61 ImageProvider.getCursor("normal", "move"));
62 putValue("toolbar", Boolean.FALSE);
63 this.layer = layer;
64 }
65
66 @Override
67 public void enterMode() {
68 super.enterMode();
69 if (layer == null)
70 return;
71 if (!layer.isVisible()) {
72 layer.setVisible(true);
73 }
74 old = layer.getDisplaySettings().getOffsetBookmark();
75 EastNorth curOff = old == null ? EastNorth.ZERO : old.getDisplacement(ProjectionRegistry.getProjection());
76 LatLon center;
77 if (MainApplication.isDisplayingMapView()) {
78 center = ProjectionRegistry.getProjection().eastNorth2latlon(MainApplication.getMap().mapView.getCenter());
79 } else {
80 center = LatLon.ZERO;
81 }
82 tempOffset = new OffsetBookmark(
83 ProjectionRegistry.getProjection().toCode(),
84 layer.getInfo().getId(),
85 layer.getInfo().getName(),
86 null,
87 curOff, center);
88 layer.getDisplaySettings().setOffsetBookmark(tempOffset);
89 addListeners();
90 showOffsetDialog(new ImageryOffsetDialog());
91 }
92
93 private static void showOffsetDialog(ImageryOffsetDialog dlg) {
94 offsetDialog = dlg;
95 offsetDialog.setVisible(true);
96 }
97
98 private static void hideOffsetDialog() {
99 offsetDialog.setVisible(false);
100 offsetDialog = null;
101 }
102
103 protected void addListeners() {
104 MapView mapView = MainApplication.getMap().mapView;
105 mapView.addMouseListener(this);
106 mapView.addMouseMotionListener(this);
107 try {
108 Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
109 } catch (SecurityException ex) {
110 Logging.error(ex);
111 }
112 }
113
114 @Override
115 public void exitMode() {
116 // do not restore old mode here - this is called when the new mode is already known.
117 restoreOldMode = false;
118 doExitMode();
119 }
120
121 private void doExitMode() {
122 exitingMode = true;
123 try {
124 super.exitMode();
125 } catch (IllegalArgumentException e) {
126 Logging.trace(e);
127 }
128 if (offsetDialog != null) {
129 if (layer != null) {
130 layer.getDisplaySettings().setOffsetBookmark(old);
131 }
132 hideOffsetDialog();
133 }
134 removeListeners();
135 exitingMode = false;
136 }
137
138 protected void removeListeners() {
139 try {
140 Toolkit.getDefaultToolkit().removeAWTEventListener(this);
141 } catch (SecurityException ex) {
142 Logging.error(ex);
143 }
144 if (MainApplication.isDisplayingMapView()) {
145 MapFrame map = MainApplication.getMap();
146 map.mapView.removeMouseMotionListener(this);
147 map.mapView.removeMouseListener(this);
148 }
149 }
150
151 @Override
152 public void eventDispatched(AWTEvent event) {
153 if (!(event instanceof KeyEvent)
154 || (event.getID() != KeyEvent.KEY_PRESSED)
155 || (layer == null)
156 || (offsetDialog != null && offsetDialog.areFieldsInFocus())) {
157 return;
158 }
159 KeyEvent kev = (KeyEvent) event;
160 int dx = 0;
161 int dy = 0;
162 switch (kev.getKeyCode()) {
163 case KeyEvent.VK_UP : dy = +1; break;
164 case KeyEvent.VK_DOWN : dy = -1; break;
165 case KeyEvent.VK_LEFT : dx = -1; break;
166 case KeyEvent.VK_RIGHT : dx = +1; break;
167 case KeyEvent.VK_ESCAPE:
168 if (offsetDialog != null) {
169 restoreOldMode = true;
170 offsetDialog.setVisible(false);
171 return;
172 }
173 break;
174 default: // Do nothing
175 }
176 if (dx != 0 || dy != 0) {
177 double ppd = layer.getPPD();
178 EastNorth d = tempOffset.getDisplacement().add(new EastNorth(dx / ppd, dy / ppd));
179 tempOffset.setDisplacement(d);
180 layer.getDisplaySettings().setOffsetBookmark(tempOffset);
181 if (offsetDialog != null) {
182 offsetDialog.updateOffset();
183 }
184 if (Logging.isDebugEnabled()) {
185 Logging.debug("{0} consuming event {1}", getClass().getName(), kev);
186 }
187 kev.consume();
188 }
189 }
190
191 @Override
192 public void mousePressed(MouseEvent e) {
193 if (e.getButton() != MouseEvent.BUTTON1)
194 return;
195
196 if (layer.isVisible()) {
197 requestFocusInMapView();
198 MapView mapView = MainApplication.getMap().mapView;
199 prevEastNorth = mapView.getEastNorth(e.getX(), e.getY());
200 mapView.setNewCursor(Cursor.MOVE_CURSOR, this);
201 }
202 }
203
204 @Override
205 public void mouseDragged(MouseEvent e) {
206 if (layer == null || prevEastNorth == null) return;
207 EastNorth eastNorth = MainApplication.getMap().mapView.getEastNorth(e.getX(), e.getY());
208 EastNorth d = tempOffset.getDisplacement().add(eastNorth).subtract(prevEastNorth);
209 tempOffset.setDisplacement(d);
210 layer.getDisplaySettings().setOffsetBookmark(tempOffset);
211 if (offsetDialog != null) {
212 offsetDialog.updateOffset();
213 }
214 prevEastNorth = eastNorth;
215 }
216
217 @Override
218 public void mouseReleased(MouseEvent e) {
219 MapView mapView = MainApplication.getMap().mapView;
220 mapView.repaint();
221 mapView.resetCursor(this);
222 prevEastNorth = null;
223 }
224
225 @Override
226 public void actionPerformed(ActionEvent e) {
227 MapFrame map = MainApplication.getMap();
228 if (offsetDialog != null || layer == null || map == null)
229 return;
230 oldMapMode = map.mapMode;
231 super.actionPerformed(e);
232 }
233
234 private static final class ConfirmOverwriteBookmarkDialog extends ExtendedDialog {
235 ConfirmOverwriteBookmarkDialog() {
236 super(MainApplication.getMainFrame(), tr("Overwrite"), tr("Overwrite"), tr("Cancel"));
237 contentInsets = new Insets(10, 15, 10, 15);
238 setContent(tr("Offset bookmark already exists. Overwrite?"));
239 setButtonIcons("ok", "cancel");
240 }
241 }
242
243 private class ImageryOffsetDialog extends ExtendedDialog implements FocusListener {
244 private final JosmTextField tOffset = new JosmTextField();
245 private final JosmTextField tBookmarkName = new JosmTextField();
246 private boolean ignoreListener;
247
248 /**
249 * Constructs a new {@code ImageryOffsetDialog}.
250 */
251 ImageryOffsetDialog() {
252 super(MainApplication.getMainFrame(),
253 tr("Adjust imagery offset"),
254 new String[] {tr("OK"), tr("Cancel")},
255 false, false); // Do not dispose on close, so HIDE_ON_CLOSE remains the default behaviour and setVisible is called
256 setButtonIcons("ok", "cancel");
257 contentInsets = new Insets(10, 15, 5, 15);
258 JPanel pnl = new JPanel(new GridBagLayout());
259 pnl.add(new JMultilineLabel(tr("Use arrow keys or drag the imagery layer with mouse to adjust the imagery offset.\n" +
260 "You can also enter east and north offset in the {0} coordinates.\n" +
261 "If you want to save the offset as bookmark, enter the bookmark name below",
262 ProjectionRegistry.getProjection().toString())), GBC.eop());
263 pnl.add(new JLabel(tr("Offset:")), GBC.std());
264 pnl.add(tOffset, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 5));
265 pnl.add(new JLabel(tr("Bookmark name: ")), GBC.std());
266 pnl.add(tBookmarkName, GBC.eol().fill(GBC.HORIZONTAL));
267 tOffset.setColumns(16);
268 updateOffsetIntl();
269 tOffset.addFocusListener(this);
270 setContent(pnl);
271 setupDialog();
272 setRememberWindowGeometry(getClass().getName() + ".geometry",
273 WindowGeometry.centerInWindow(MainApplication.getMainFrame(), getSize()));
274 }
275
276 private boolean areFieldsInFocus() {
277 return tOffset.hasFocus();
278 }
279
280 @Override
281 public void focusGained(FocusEvent e) {
282 // Do nothing
283 }
284
285 @Override
286 public void focusLost(FocusEvent e) {
287 if (ignoreListener) return;
288 String ostr = tOffset.getText();
289 int semicolon = ostr.indexOf(';');
290 if (layer != null && semicolon >= 0 && semicolon + 1 < ostr.length()) {
291 try {
292 String easting = ostr.substring(0, semicolon).trim();
293 String northing = ostr.substring(semicolon + 1).trim();
294 double dx = JosmDecimalFormatSymbolsProvider.parseDouble(easting);
295 double dy = JosmDecimalFormatSymbolsProvider.parseDouble(northing);
296 tempOffset.setDisplacement(new EastNorth(dx, dy));
297 layer.getDisplaySettings().setOffsetBookmark(tempOffset);
298 } catch (NumberFormatException nfe) {
299 // we repaint offset numbers in any case
300 Logging.trace(nfe);
301 }
302 }
303 updateOffsetIntl();
304 if (layer != null) {
305 layer.invalidate();
306 }
307 }
308
309 private void updateOffset() {
310 ignoreListener = true;
311 updateOffsetIntl();
312 ignoreListener = false;
313 }
314
315 private void updateOffsetIntl() {
316 if (layer != null) {
317 // ROOT locale to force decimal separator to be '.'
318 tOffset.setText(layer.getDisplaySettings().getDisplacementString(Locale.ROOT));
319 }
320 }
321
322 private boolean confirmOverwriteBookmark() {
323 return new ConfirmOverwriteBookmarkDialog().showDialog().getValue() == 1;
324 }
325
326 @Override
327 protected void buttonAction(int buttonIndex, ActionEvent evt) {
328 restoreOldMode = true;
329 if (buttonIndex == 0 && tBookmarkName.getText() != null && !tBookmarkName.getText().isEmpty() &&
330 OffsetBookmark.getBookmarkByName(layer, tBookmarkName.getText()) != null &&
331 !confirmOverwriteBookmark()) {
332 return;
333 }
334 super.buttonAction(buttonIndex, evt);
335 }
336
337 @Override
338 public void setVisible(boolean visible) {
339 super.setVisible(visible);
340 if (visible)
341 return;
342 ignoreListener = true;
343 offsetDialog = null;
344 if (layer != null) {
345 if (getValue() != 1) {
346 layer.getDisplaySettings().setOffsetBookmark(old);
347 } else if (tBookmarkName.getText() != null && !tBookmarkName.getText().isEmpty()) {
348 OffsetBookmark.bookmarkOffset(tBookmarkName.getText(), layer);
349 }
350 }
351 MainApplication.getMenu().imageryMenu.refreshOffsetMenu();
352 restoreMapModeState();
353 }
354
355 private void restoreMapModeState() {
356 MapFrame map = MainApplication.getMap();
357 if (map == null)
358 return;
359 if (oldMapMode != null) {
360 if (restoreOldMode || (!exitingMode && getValue() == ExtendedDialog.DialogClosedOtherwise)) {
361 map.selectMapMode(oldMapMode);
362 }
363 oldMapMode = null;
364 } else if (!exitingMode && !map.selectSelectTool(false)) {
365 exitModeAndRestoreOldMode();
366 map.mapMode = null;
367 }
368 }
369
370 private void exitModeAndRestoreOldMode() {
371 restoreOldMode = true;
372 doExitMode();
373 restoreOldMode = false;
374 }
375 }
376
377 @Override
378 public void destroy() {
379 super.destroy();
380 removeListeners();
381 this.layer = null;
382 this.oldMapMode = null;
383 }
384}
Note: See TracBrowser for help on using the repository browser.