altosui: Make sure degree and minute values are visible (map preload)
[fw/altos] / altosui / AltosSiteMapPreload.java
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package altosui;
19
20 import java.awt.*;
21 import java.awt.image.*;
22 import java.awt.event.*;
23 import javax.swing.*;
24 import javax.swing.event.MouseInputAdapter;
25 import javax.imageio.ImageIO;
26 import javax.swing.table.*;
27 import java.io.*;
28 import java.util.*;
29 import java.text.*;
30 import java.util.prefs.*;
31 import java.lang.Math;
32 import java.awt.geom.Point2D;
33 import java.awt.geom.Line2D;
34
35 class AltosMapPos extends Box {
36         AltosUI         owner;
37         JLabel          label;
38         JComboBox       hemi;
39         JTextField      deg;
40         JLabel          deg_label;
41         JTextField      min;
42         JLabel          min_label;
43
44         public void set_value(double new_value) {
45                 double  d, m;
46                 int     h;
47
48                 h = 0;
49                 if (new_value < 0) {
50                         h = 1;
51                         new_value = -new_value;
52                 }
53                 d = Math.floor(new_value);
54                 deg.setText(String.format("%3.0f", d));
55                 m = (new_value - d) * 60.0;
56                 min.setText(String.format("%7.4f", m));
57                 hemi.setSelectedIndex(h);
58         }
59
60         public double get_value() throws NumberFormatException {
61                 int     h = hemi.getSelectedIndex();
62                 String  d_t = deg.getText();
63                 String  m_t = min.getText();
64                 double  d, m, v;
65                 try {
66                         d = Double.parseDouble(d_t);
67                 } catch (NumberFormatException ne) {
68                         JOptionPane.showMessageDialog(owner,
69                                                       String.format("Invalid degrees \"%s\"",
70                                                                     d_t),
71                                                       "Invalid number",
72                                                       JOptionPane.ERROR_MESSAGE);
73                         throw ne;
74                 }
75                 try {
76                         if (m_t.equals(""))
77                                 m = 0;
78                         else
79                                 m = Double.parseDouble(m_t);
80                 } catch (NumberFormatException ne) {
81                         JOptionPane.showMessageDialog(owner,
82                                                       String.format("Invalid minutes \"%s\"",
83                                                                     m_t),
84                                                       "Invalid number",
85                                                       JOptionPane.ERROR_MESSAGE);
86                         throw ne;
87                 }
88                 v = d + m/60.0;
89                 if (h == 1)
90                         v = -v;
91                 return v;
92         }
93
94         public AltosMapPos(AltosUI in_owner,
95                            String label_value,
96                            String[] hemi_names,
97                            double default_value) {
98                 super(BoxLayout.X_AXIS);
99                 owner = in_owner;
100                 label = new JLabel(label_value);
101                 hemi = new JComboBox(hemi_names);
102                 hemi.setEditable(false);
103                 deg = new JTextField("000");
104                 deg_label = new JLabel("°");
105                 min = new JTextField("00.0000");
106                 min_label = new JLabel("'");
107                 set_value(default_value);
108                 deg.setMinimumSize(deg.getPreferredSize());
109                 min.setMinimumSize(min.getPreferredSize());
110                 add(label);
111                 add(Box.createRigidArea(new Dimension(5, 0)));
112                 add(hemi);
113                 add(Box.createRigidArea(new Dimension(5, 0)));
114                 add(deg);
115                 add(Box.createRigidArea(new Dimension(5, 0)));
116                 add(deg_label);
117                 add(Box.createRigidArea(new Dimension(5, 0)));
118                 add(min);
119                 add(Box.createRigidArea(new Dimension(5, 0)));
120                 add(min_label);
121         }
122 }
123
124 public class AltosSiteMapPreload extends JDialog implements ActionListener {
125         AltosUI         owner;
126         AltosSiteMap    map;
127
128         AltosMapPos     lat;
129         AltosMapPos     lon;
130
131         JProgressBar    pbar;
132
133         final static int        radius = 4;
134         final static int        width = (radius * 2 + 1);
135         final static int        height = (radius * 2 + 1);
136
137         JToggleButton   load_button;
138         boolean         loading;
139         JButton         close_button;
140
141         static final String[]   lat_hemi_names = { "N", "S" };
142         static final String[]   lon_hemi_names = { "E", "W" };
143
144         class updatePbar implements Runnable {
145                 int             n;
146                 String          s;
147
148                 public updatePbar(int x, int y, String in_s) {
149                         n = (x + radius) + (y + radius) * width + 1;
150                         s = in_s;
151                 }
152
153                 public void run() {
154                         pbar.setValue(n);
155                         pbar.setString(s);
156                         if (n < width * height) {
157                                 pbar.setValue(n);
158                                 pbar.setString(s);
159                         } else {
160                                 pbar.setValue(0);
161                                 pbar.setString("");
162                                 load_button.setSelected(false);
163                                 loading = false;
164                         }
165                 }
166         }
167
168         class bgLoad extends Thread {
169
170                 AltosSiteMap    map;
171
172                 public bgLoad(AltosSiteMap in_map) {
173                         map = in_map;
174                 }
175
176                 public void run() {
177                         for (int y = -map.radius; y <= map.radius; y++) {
178                                 for (int x = -map.radius; x <= map.radius; x++) {
179                                         String  pngfile;
180                                         pngfile = map.initMap(new Point(x,y));
181                                         SwingUtilities.invokeLater(new updatePbar(x, y, pngfile));
182                                 }
183                         }
184                 }
185         }
186
187         public void actionPerformed(ActionEvent e) {
188                 String  cmd = e.getActionCommand();
189
190                 if (cmd.equals("close"))
191                         setVisible(false);
192
193                 if (cmd.equals("load")) {
194                         if (!loading) {
195                                 try {
196                                         final double    latitude = lat.get_value();
197                                         final double    longitude = lon.get_value();
198                                         map.setBaseLocation(latitude,longitude);
199                                         loading = true;
200                                         bgLoad thread = new bgLoad(map);
201                                         thread.start();
202                                 } catch (NumberFormatException ne) {
203                                         load_button.setSelected(false);
204                                 }
205                         }
206                 }
207         }
208
209         public AltosSiteMapPreload(AltosUI in_owner) {
210                 owner = in_owner;
211
212                 Container               pane = getContentPane();
213                 GridBagConstraints      c = new GridBagConstraints();
214                 Insets                  i = new Insets(4,4,4,4);
215
216                 pane.setLayout(new GridBagLayout());
217
218                 map = new AltosSiteMap(4);
219
220                 c.fill = GridBagConstraints.BOTH;
221                 c.anchor = GridBagConstraints.CENTER;
222                 c.insets = i;
223                 c.weightx = 1;
224                 c.weighty = 1;
225
226                 c.gridx = 0;
227                 c.gridy = 0;
228                 c.gridwidth = 2;
229                 c.anchor = GridBagConstraints.CENTER;
230
231                 pane.add(map, c);
232
233                 pbar = new JProgressBar();
234                 pbar.setMinimum(0);
235                 pbar.setMaximum(width * height);
236                 pbar.setValue(0);
237                 pbar.setString("");
238                 pbar.setStringPainted(true);
239                 
240                 c.fill = GridBagConstraints.HORIZONTAL;
241                 c.anchor = GridBagConstraints.CENTER;
242                 c.insets = i;
243                 c.weightx = 1;
244                 c.weighty = 0;
245
246                 c.gridx = 0;
247                 c.gridy = 1;
248                 c.gridwidth = 2;
249
250                 pane.add(pbar, c);
251
252                 lat = new AltosMapPos(owner,
253                                       "Latitude:",
254                                       lat_hemi_names,
255                                       37.167833333);
256                 c.fill = GridBagConstraints.NONE;
257                 c.anchor = GridBagConstraints.CENTER;
258                 c.insets = i;
259                 c.weightx = 0;
260                 c.weighty = 0;
261
262                 c.gridx = 0;
263                 c.gridy = 2;
264                 c.gridwidth = 1;
265                 c.anchor = GridBagConstraints.CENTER;
266
267                 pane.add(lat, c);
268                 
269                 lon = new AltosMapPos(owner,
270                                       "Longitude:",
271                                       lon_hemi_names,
272                                       -97.73975);
273
274                 c.fill = GridBagConstraints.NONE;
275                 c.anchor = GridBagConstraints.CENTER;
276                 c.insets = i;
277                 c.weightx = 0;
278                 c.weighty = 0;
279
280                 c.gridx = 1;
281                 c.gridy = 2;
282                 c.gridwidth = 1;
283                 c.anchor = GridBagConstraints.CENTER;
284
285                 pane.add(lon, c);
286
287                 load_button = new JToggleButton("Load Map");
288                 load_button.addActionListener(this);
289                 load_button.setActionCommand("load");
290                 
291                 c.fill = GridBagConstraints.NONE;
292                 c.anchor = GridBagConstraints.CENTER;
293                 c.insets = i;
294                 c.weightx = 1;
295                 c.weighty = 0;
296
297                 c.gridx = 0;
298                 c.gridy = 3;
299                 c.gridwidth = 1;
300                 c.anchor = GridBagConstraints.CENTER;
301
302                 pane.add(load_button, c);
303
304                 close_button = new JButton("Close");
305                 close_button.addActionListener(this);
306                 close_button.setActionCommand("close");
307                 
308                 c.fill = GridBagConstraints.NONE;
309                 c.anchor = GridBagConstraints.CENTER;
310                 c.insets = i;
311                 c.weightx = 1;
312                 c.weighty = 0;
313
314                 c.gridx = 1;
315                 c.gridy = 3;
316                 c.gridwidth = 1;
317                 c.anchor = GridBagConstraints.CENTER;
318
319                 pane.add(close_button, c);
320
321                 pack();
322                 setLocationRelativeTo(owner);
323                 setVisible(true);
324         }
325 }