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

Last change on this file since 2403 was 2403, checked in by Gubaer, 14 years ago

fixed #454: Right-click context menus in download text-entry boxes

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