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

Last change on this file since 13766 was 13761, checked in by Don-vip, 6 years ago

see #16288 - replace similar i18n strings (removes 35 strings from Launchpad)

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