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

Last change on this file since 2512 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

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