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

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

fix #5235 - patch by Upliner - button to clear URL dropbox

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