source: josm/trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java@ 17318

Last change on this file since 17318 was 15756, checked in by GerdP, 4 years ago

fix pmd issue: Array initialization can be written shorter.

  • Property svn:eol-style set to native
File size: 11.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.download;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Color;
8import java.awt.Dimension;
9import java.awt.GridBagLayout;
10import java.awt.Panel;
11import java.awt.event.ActionEvent;
12import java.awt.event.ActionListener;
13import java.awt.event.FocusAdapter;
14import java.awt.event.FocusEvent;
15import java.awt.event.MouseAdapter;
16import java.awt.event.MouseEvent;
17
18import javax.swing.BorderFactory;
19import javax.swing.JButton;
20import javax.swing.JLabel;
21import javax.swing.JPanel;
22import javax.swing.UIManager;
23import javax.swing.border.Border;
24import javax.swing.event.DocumentEvent;
25import javax.swing.event.DocumentListener;
26import javax.swing.text.JTextComponent;
27
28import org.openstreetmap.josm.data.Bounds;
29import org.openstreetmap.josm.data.coor.LatLon;
30import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
31import org.openstreetmap.josm.gui.widgets.JosmTextArea;
32import org.openstreetmap.josm.gui.widgets.JosmTextField;
33import org.openstreetmap.josm.tools.GBC;
34import org.openstreetmap.josm.tools.JosmDecimalFormatSymbolsProvider;
35import org.openstreetmap.josm.tools.Logging;
36import org.openstreetmap.josm.tools.OsmUrlToBounds;
37
38/**
39 * Bounding box selector.
40 *
41 * Provides max/min lat/lon input fields as well as the "URL from www.openstreetmap.org" text field.
42 *
43 * @author Frederik Ramm
44 *
45 */
46public class BoundingBoxSelection implements DownloadSelection {
47
48 private JosmTextField[] latlon;
49 private final JosmTextArea tfOsmUrl = new JosmTextArea();
50 private final JosmTextArea showUrl = new JosmTextArea();
51 private DownloadDialog parent;
52
53 protected void registerBoundingBoxBuilder() {
54 BoundingBoxBuilder bboxbuilder = new BoundingBoxBuilder();
55 for (JosmTextField ll : latlon) {
56 ll.addFocusListener(bboxbuilder);
57 ll.addActionListener(bboxbuilder);
58 }
59 }
60
61 protected void buildDownloadAreaInputFields() {
62 latlon = new JosmTextField[4];
63 for (int i = 0; i < 4; i++) {
64 latlon[i] = new JosmTextField(11);
65 latlon[i].setMinimumSize(new Dimension(100, new JosmTextField().getMinimumSize().height));
66 latlon[i].addFocusListener(new SelectAllOnFocusHandler(latlon[i]));
67 }
68 LatValueChecker latChecker = new LatValueChecker(latlon[0]);
69 latlon[0].addFocusListener(latChecker);
70 latlon[0].addActionListener(latChecker);
71
72 latChecker = new LatValueChecker(latlon[2]);
73 latlon[2].addFocusListener(latChecker);
74 latlon[2].addActionListener(latChecker);
75
76 LonValueChecker lonChecker = new LonValueChecker(latlon[1]);
77 latlon[1].addFocusListener(lonChecker);
78 latlon[1].addActionListener(lonChecker);
79
80 lonChecker = new LonValueChecker(latlon[3]);
81 latlon[3].addFocusListener(lonChecker);
82 latlon[3].addActionListener(lonChecker);
83
84 registerBoundingBoxBuilder();
85 }
86
87 @Override
88 public void addGui(final DownloadDialog gui) {
89 buildDownloadAreaInputFields();
90 final JPanel dlg = new JPanel(new GridBagLayout());
91
92 tfOsmUrl.getDocument().addDocumentListener(new OsmUrlRefresher());
93
94 // select content on receiving focus. this seems to be the default in the
95 // windows look+feel but not for others. needs invokeLater to avoid strange
96 // side effects that will cancel out the newly made selection otherwise.
97 tfOsmUrl.addFocusListener(new SelectAllOnFocusHandler(tfOsmUrl));
98 tfOsmUrl.setLineWrap(true);
99 tfOsmUrl.setBorder(latlon[0].getBorder());
100
101 final Panel latlonPanel = new Panel(new BorderLayout());
102 final String[] labels = {tr("min lat"), tr("min lon"), tr("max lat"), tr("max lon")};
103 final String[] positions = {BorderLayout.SOUTH, BorderLayout.WEST, BorderLayout.NORTH, BorderLayout.EAST};
104 for (int i = 0; i < latlon.length; i++) {
105 final Panel panel = new Panel(new GridBagLayout());
106 panel.add(new JLabel(labels[i]), GBC.std().insets(10, 0, 3, 0));
107 panel.add(latlon[i]);
108 latlonPanel.add(panel, positions[i]);
109 }
110 dlg.add(latlonPanel, GBC.eop().insets(0, 20, 0, 0));
111
112 final JButton btnClear = new JButton(tr("Clear textarea"));
113 btnClear.addMouseListener(new MouseAdapter() {
114 @Override
115 public void mouseClicked(MouseEvent arg0) {
116 tfOsmUrl.setText("");
117 }
118 });
119 dlg.add(btnClear, GBC.eol().insets(10, 20, 0, 0));
120
121 dlg.add(new JLabel(tr("URL from www.openstreetmap.org (you can paste an URL here to download the area)")),
122 GBC.eol().insets(10, 5, 5, 0));
123 dlg.add(tfOsmUrl, GBC.eop().insets(10, 0, 5, 0).fill());
124 dlg.add(showUrl, GBC.eop().insets(10, 0, 5, 5));
125 showUrl.setEditable(false);
126 showUrl.setBackground(dlg.getBackground());
127 showUrl.addFocusListener(new SelectAllOnFocusHandler(showUrl));
128
129 if (gui != null)
130 gui.addDownloadAreaSelector(dlg, tr("Bounding Box"));
131 this.parent = gui;
132 }
133
134 @Override
135 public void setDownloadArea(Bounds area) {
136 updateBboxFields(area);
137 updateUrl(area);
138 }
139
140 /**
141 * Replies the download area.
142 * @return The download area
143 */
144 public Bounds getDownloadArea() {
145 double[] values = new double[4];
146 for (int i = 0; i < 4; i++) {
147 try {
148 values[i] = JosmDecimalFormatSymbolsProvider.parseDouble(latlon[i].getText());
149 } catch (NumberFormatException ex) {
150 return null;
151 }
152 }
153 if (!LatLon.isValidLat(values[0]) || !LatLon.isValidLon(values[1]))
154 return null;
155 if (!LatLon.isValidLat(values[2]) || !LatLon.isValidLon(values[3]))
156 return null;
157 return new Bounds(values);
158 }
159
160 private boolean parseURL(DownloadDialog gui) {
161 Bounds b = OsmUrlToBounds.parse(tfOsmUrl.getText());
162 if (b == null) return false;
163 gui.boundingBoxChanged(b, this);
164 updateBboxFields(b);
165 updateUrl(b);
166 return true;
167 }
168
169 private void updateBboxFields(Bounds area) {
170 if (area == null) return;
171 latlon[0].setText(DecimalDegreesCoordinateFormat.INSTANCE.latToString(area.getMin()));
172 latlon[1].setText(DecimalDegreesCoordinateFormat.INSTANCE.lonToString(area.getMin()));
173 latlon[2].setText(DecimalDegreesCoordinateFormat.INSTANCE.latToString(area.getMax()));
174 latlon[3].setText(DecimalDegreesCoordinateFormat.INSTANCE.lonToString(area.getMax()));
175 for (JosmTextField tf: latlon) {
176 resetErrorMessage(tf);
177 }
178 }
179
180 private void updateUrl(Bounds area) {
181 if (area == null) return;
182 showUrl.setText(OsmUrlToBounds.getURL(area));
183 }
184
185 private final Border errorBorder = BorderFactory.createLineBorder(Color.RED, 1);
186
187 protected void setErrorMessage(JosmTextField tf, String msg) {
188 tf.setBorder(errorBorder);
189 tf.setToolTipText(msg);
190 }
191
192 protected void resetErrorMessage(JosmTextField tf) {
193 tf.setBorder(UIManager.getBorder("TextField.border"));
194 tf.setToolTipText(null);
195 }
196
197 class LatValueChecker extends FocusAdapter implements ActionListener {
198 private final JosmTextField tfLatValue;
199
200 LatValueChecker(JosmTextField tfLatValue) {
201 this.tfLatValue = tfLatValue;
202 }
203
204 protected void check() {
205 double value = 0;
206 try {
207 value = JosmDecimalFormatSymbolsProvider.parseDouble(tfLatValue.getText());
208 } catch (NumberFormatException ex) {
209 setErrorMessage(tfLatValue, tr("The string ''{0}'' is not a valid double value.", tfLatValue.getText()));
210 return;
211 }
212 if (!LatLon.isValidLat(value)) {
213 setErrorMessage(tfLatValue, tr("Value for latitude in range [-90,90] required.", tfLatValue.getText()));
214 return;
215 }
216 resetErrorMessage(tfLatValue);
217 }
218
219 @Override
220 public void focusLost(FocusEvent e) {
221 check();
222 }
223
224 @Override
225 public void actionPerformed(ActionEvent e) {
226 check();
227 }
228 }
229
230 class LonValueChecker extends FocusAdapter implements ActionListener {
231 private final JosmTextField tfLonValue;
232
233 LonValueChecker(JosmTextField tfLonValue) {
234 this.tfLonValue = tfLonValue;
235 }
236
237 protected void check() {
238 double value = 0;
239 try {
240 value = JosmDecimalFormatSymbolsProvider.parseDouble(tfLonValue.getText());
241 } catch (NumberFormatException ex) {
242 setErrorMessage(tfLonValue, tr("The string ''{0}'' is not a valid double value.", tfLonValue.getText()));
243 return;
244 }
245 if (!LatLon.isValidLon(value)) {
246 setErrorMessage(tfLonValue, tr("Value for longitude in range [-180,180] required.", tfLonValue.getText()));
247 return;
248 }
249 resetErrorMessage(tfLonValue);
250 }
251
252 @Override
253 public void focusLost(FocusEvent e) {
254 check();
255 }
256
257 @Override
258 public void actionPerformed(ActionEvent e) {
259 check();
260 }
261 }
262
263 static class SelectAllOnFocusHandler extends FocusAdapter {
264 private final JTextComponent tfTarget;
265
266 SelectAllOnFocusHandler(JTextComponent tfTarget) {
267 this.tfTarget = tfTarget;
268 }
269
270 @Override
271 public void focusGained(FocusEvent e) {
272 tfTarget.selectAll();
273 }
274 }
275
276 class OsmUrlRefresher implements DocumentListener {
277 @Override
278 public void changedUpdate(DocumentEvent e) {
279 parseURL(parent);
280 }
281
282 @Override
283 public void insertUpdate(DocumentEvent e) {
284 parseURL(parent);
285 }
286
287 @Override
288 public void removeUpdate(DocumentEvent e) {
289 parseURL(parent);
290 }
291 }
292
293 class BoundingBoxBuilder extends FocusAdapter implements ActionListener {
294 protected Bounds build() {
295 double minlon, minlat, maxlon, maxlat;
296 try {
297 minlat = JosmDecimalFormatSymbolsProvider.parseDouble(latlon[0].getText().trim());
298 minlon = JosmDecimalFormatSymbolsProvider.parseDouble(latlon[1].getText().trim());
299 maxlat = JosmDecimalFormatSymbolsProvider.parseDouble(latlon[2].getText().trim());
300 maxlon = JosmDecimalFormatSymbolsProvider.parseDouble(latlon[3].getText().trim());
301 } catch (NumberFormatException e) {
302 Logging.trace(e);
303 return null;
304 }
305 if (!LatLon.isValidLon(minlon) || !LatLon.isValidLon(maxlon)
306 || !LatLon.isValidLat(minlat) || !LatLon.isValidLat(maxlat))
307 return null;
308 if (minlon > maxlon)
309 return null;
310 if (minlat > maxlat)
311 return null;
312 return new Bounds(minlat, minlon, maxlat, maxlon);
313 }
314
315 protected void refreshBounds() {
316 Bounds b = build();
317 parent.boundingBoxChanged(b, BoundingBoxSelection.this);
318 }
319
320 @Override
321 public void focusLost(FocusEvent e) {
322 refreshBounds();
323 }
324
325 @Override
326 public void actionPerformed(ActionEvent e) {
327 refreshBounds();
328 }
329 }
330}
Note: See TracBrowser for help on using the repository browser.