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

Last change on this file since 7402 was 7350, checked in by Don-vip, 10 years ago

fix #10322 - NPE

  • Property svn:eol-style set to native
File size: 10.6 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.awt.event.MouseListener;
18import java.awt.event.MouseMotionListener;
19import java.util.Formatter;
20import java.util.Locale;
21
22import javax.swing.JLabel;
23import javax.swing.JPanel;
24
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.actions.mapmode.MapMode;
27import org.openstreetmap.josm.data.coor.EastNorth;
28import org.openstreetmap.josm.data.imagery.OffsetBookmark;
29import org.openstreetmap.josm.gui.ExtendedDialog;
30import org.openstreetmap.josm.gui.layer.ImageryLayer;
31import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
32import org.openstreetmap.josm.gui.widgets.JosmTextField;
33import org.openstreetmap.josm.tools.GBC;
34import org.openstreetmap.josm.tools.ImageProvider;
35
36public class ImageryAdjustAction extends MapMode implements MouseListener, MouseMotionListener, AWTEventListener{
37 static ImageryOffsetDialog offsetDialog;
38 static Cursor cursor = ImageProvider.getCursor("normal", "move");
39
40 double oldDx, oldDy;
41 boolean mouseDown;
42 EastNorth prevEastNorth;
43 private ImageryLayer layer;
44 private MapMode oldMapMode;
45
46 /**
47 * Constructs a new {@code ImageryAdjustAction} for the given layer.
48 * @param layer The imagery layer
49 */
50 public ImageryAdjustAction(ImageryLayer layer) {
51 super(tr("New offset"), "adjustimg",
52 tr("Adjust the position of this imagery layer"), Main.map,
53 cursor);
54 putValue("toolbar", false);
55 this.layer = layer;
56 }
57
58 @Override
59 public void enterMode() {
60 super.enterMode();
61 if (layer == null)
62 return;
63 if (!layer.isVisible()) {
64 layer.setVisible(true);
65 }
66 oldDx = layer.getDx();
67 oldDy = layer.getDy();
68 addListeners();
69 offsetDialog = new ImageryOffsetDialog();
70 offsetDialog.setVisible(true);
71 }
72
73 protected void addListeners() {
74 Main.map.mapView.addMouseListener(this);
75 Main.map.mapView.addMouseMotionListener(this);
76 try {
77 Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
78 } catch (SecurityException ex) {
79 Main.error(ex);
80 }
81 }
82
83 @Override
84 public void exitMode() {
85 super.exitMode();
86 if (offsetDialog != null) {
87 if (layer != null) {
88 layer.setOffset(oldDx, oldDy);
89 }
90 offsetDialog.setVisible(false);
91 offsetDialog = null;
92 }
93 removeListeners();
94 }
95
96 protected void removeListeners() {
97 try {
98 Toolkit.getDefaultToolkit().removeAWTEventListener(this);
99 } catch (SecurityException ex) {
100 Main.error(ex);
101 }
102 if (Main.isDisplayingMapView()) {
103 Main.map.mapView.removeMouseMotionListener(this);
104 Main.map.mapView.removeMouseListener(this);
105 }
106 }
107
108 @Override
109 public void eventDispatched(AWTEvent event) {
110 if (!(event instanceof KeyEvent)) return;
111 if (event.getID() != KeyEvent.KEY_PRESSED) return;
112 if (layer == null) return;
113 if (offsetDialog != null && offsetDialog.areFieldsInFocus()) return;
114 KeyEvent kev = (KeyEvent)event;
115 double dx = 0, dy = 0;
116 switch (kev.getKeyCode()) {
117 case KeyEvent.VK_UP : dy = +1; break;
118 case KeyEvent.VK_DOWN : dy = -1; break;
119 case KeyEvent.VK_LEFT : dx = -1; break;
120 case KeyEvent.VK_RIGHT : dx = +1; break;
121 }
122 if (dx != 0 || dy != 0) {
123 double ppd = layer.getPPD();
124 layer.displace(dx / ppd, dy / ppd);
125 if (offsetDialog != null) {
126 offsetDialog.updateOffset();
127 }
128 kev.consume();
129 Main.map.repaint();
130 }
131 }
132
133 @Override
134 public void mousePressed(MouseEvent e) {
135 if (e.getButton() != MouseEvent.BUTTON1)
136 return;
137
138 if (layer.isVisible()) {
139 requestFocusInMapView();
140 prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
141 Main.map.mapView.setNewCursor(Cursor.MOVE_CURSOR, this);
142 }
143 }
144
145 @Override
146 public void mouseDragged(MouseEvent e) {
147 if (layer == null || prevEastNorth == null) return;
148 EastNorth eastNorth =
149 Main.map.mapView.getEastNorth(e.getX(),e.getY());
150 double dx = layer.getDx()+eastNorth.east()-prevEastNorth.east();
151 double dy = layer.getDy()+eastNorth.north()-prevEastNorth.north();
152 layer.setOffset(dx, dy);
153 if (offsetDialog != null) {
154 offsetDialog.updateOffset();
155 }
156 Main.map.repaint();
157 prevEastNorth = eastNorth;
158 }
159
160 @Override
161 public void mouseReleased(MouseEvent e) {
162 Main.map.mapView.repaint();
163 Main.map.mapView.resetCursor(this);
164 prevEastNorth = null;
165 }
166
167 @Override
168 public void actionPerformed(ActionEvent e) {
169 if (offsetDialog != null || layer == null || Main.map == null)
170 return;
171 oldMapMode = Main.map.mapMode;
172 super.actionPerformed(e);
173 }
174
175 class ImageryOffsetDialog extends ExtendedDialog implements FocusListener {
176 public final JosmTextField tOffset = new JosmTextField();
177 JosmTextField tBookmarkName = new JosmTextField();
178 private boolean ignoreListener;
179 public ImageryOffsetDialog() {
180 super(Main.parent,
181 tr("Adjust imagery offset"),
182 new String[] { tr("OK"),tr("Cancel") },
183 false);
184 setButtonIcons(new String[] { "ok", "cancel" });
185 contentInsets = new Insets(10, 15, 5, 15);
186 JPanel pnl = new JPanel(new GridBagLayout());
187 pnl.add(new JMultilineLabel(tr("Use arrow keys or drag the imagery layer with mouse to adjust the imagery offset.\n" +
188 "You can also enter east and north offset in the {0} coordinates.\n" +
189 "If you want to save the offset as bookmark, enter the bookmark name below",Main.getProjection().toString())), GBC.eop());
190 pnl.add(new JLabel(tr("Offset: ")),GBC.std());
191 pnl.add(tOffset,GBC.eol().fill(GBC.HORIZONTAL).insets(0,0,0,5));
192 pnl.add(new JLabel(tr("Bookmark name: ")),GBC.std());
193 pnl.add(tBookmarkName,GBC.eol().fill(GBC.HORIZONTAL));
194 tOffset.setColumns(16);
195 updateOffsetIntl();
196 tOffset.addFocusListener(this);
197 setContent(pnl);
198 setupDialog();
199 }
200
201 public boolean areFieldsInFocus() {
202 return tOffset.hasFocus();
203 }
204
205 @Override
206 public void focusGained(FocusEvent e) {
207 }
208
209 @Override
210 public void focusLost(FocusEvent e) {
211 if (ignoreListener) return;
212 String ostr = tOffset.getText();
213 int semicolon = ostr.indexOf(';');
214 if( semicolon >= 0 && semicolon + 1 < ostr.length() ) {
215 try {
216 // here we assume that Double.parseDouble() needs '.' as a decimal separator
217 String easting = ostr.substring(0, semicolon).trim().replace(',', '.');
218 String northing = ostr.substring(semicolon + 1).trim().replace(',', '.');
219 double dx = Double.parseDouble(easting);
220 double dy = Double.parseDouble(northing);
221 layer.setOffset(dx, dy);
222 } catch (NumberFormatException nfe) {
223 // we repaint offset numbers in any case
224 }
225 }
226 updateOffsetIntl();
227 if (Main.isDisplayingMapView()) {
228 Main.map.repaint();
229 }
230 }
231
232 public final void updateOffset() {
233 ignoreListener = true;
234 updateOffsetIntl();
235 ignoreListener = false;
236 }
237
238 public final void updateOffsetIntl() {
239 // Support projections with very small numbers (e.g. 4326)
240 int precision = Main.getProjection().getDefaultZoomInPPD() >= 1.0 ? 2 : 7;
241 // US locale to force decimal separator to be '.'
242 try (Formatter us = new Formatter(Locale.US)) {
243 tOffset.setText(us.format(
244 "%1." + precision + "f; %1." + precision + "f",
245 layer.getDx(), layer.getDy()).toString());
246 }
247 }
248
249 private boolean confirmOverwriteBookmark() {
250 ExtendedDialog dialog = new ExtendedDialog(
251 Main.parent,
252 tr("Overwrite"),
253 new String[] {tr("Overwrite"), tr("Cancel")}
254 ) {{
255 contentInsets = new Insets(10, 15, 10, 15);
256 }};
257 dialog.setContent(tr("Offset bookmark already exists. Overwrite?"));
258 dialog.setButtonIcons(new String[] {"ok.png", "cancel.png"});
259 dialog.setupDialog();
260 dialog.setVisible(true);
261 return dialog.getValue() == 1;
262 }
263
264 @Override
265 protected void buttonAction(int buttonIndex, ActionEvent evt) {
266 if (buttonIndex == 0 && tBookmarkName.getText() != null && !tBookmarkName.getText().isEmpty() &&
267 OffsetBookmark.getBookmarkByName(layer, tBookmarkName.getText()) != null) {
268 if (!confirmOverwriteBookmark()) return;
269 }
270 super.buttonAction(buttonIndex, evt);
271 }
272
273 @Override
274 public void setVisible(boolean visible) {
275 super.setVisible(visible);
276 if (visible) return;
277 offsetDialog = null;
278 if (getValue() != 1) {
279 layer.setOffset(oldDx, oldDy);
280 } else if (tBookmarkName.getText() != null && !tBookmarkName.getText().isEmpty()) {
281 OffsetBookmark.bookmarkOffset(tBookmarkName.getText(), layer);
282 }
283 Main.main.menu.imageryMenu.refreshOffsetMenu();
284 if (Main.map == null) return;
285 if (oldMapMode != null) {
286 Main.map.selectMapMode(oldMapMode);
287 oldMapMode = null;
288 } else {
289 Main.map.selectSelectTool(false);
290 }
291 }
292 }
293
294 @Override
295 public void destroy() {
296 super.destroy();
297 removeListeners();
298 this.layer = null;
299 this.oldMapMode = null;
300 }
301}
Note: See TracBrowser for help on using the repository browser.