altos: Need to use 16-bit counts for ao_xmem functions
[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 import java.net.URL;
35 import java.net.URLConnection;
36 import org.altusmetrum.AltosLib.*;
37
38 class AltosMapPos extends Box {
39         AltosUI         owner;
40         JLabel          label;
41         JComboBox       hemi;
42         JTextField      deg;
43         JLabel          deg_label;
44         JTextField      min;
45         JLabel          min_label;
46
47         public void set_value(double new_value) {
48                 double  d, m;
49                 int     h;
50
51                 h = 0;
52                 if (new_value < 0) {
53                         h = 1;
54                         new_value = -new_value;
55                 }
56                 d = Math.floor(new_value);
57                 deg.setText(String.format("%3.0f", d));
58                 m = (new_value - d) * 60.0;
59                 min.setText(String.format("%7.4f", m));
60                 hemi.setSelectedIndex(h);
61         }
62
63         public double get_value() throws NumberFormatException {
64                 int     h = hemi.getSelectedIndex();
65                 String  d_t = deg.getText();
66                 String  m_t = min.getText();
67                 double  d, m, v;
68                 try {
69                         d = Double.parseDouble(d_t);
70                 } catch (NumberFormatException ne) {
71                         JOptionPane.showMessageDialog(owner,
72                                                       String.format("Invalid degrees \"%s\"",
73                                                                     d_t),
74                                                       "Invalid number",
75                                                       JOptionPane.ERROR_MESSAGE);
76                         throw ne;
77                 }
78                 try {
79                         if (m_t.equals(""))
80                                 m = 0;
81                         else
82                                 m = Double.parseDouble(m_t);
83                 } catch (NumberFormatException ne) {
84                         JOptionPane.showMessageDialog(owner,
85                                                       String.format("Invalid minutes \"%s\"",
86                                                                     m_t),
87                                                       "Invalid number",
88                                                       JOptionPane.ERROR_MESSAGE);
89                         throw ne;
90                 }
91                 v = d + m/60.0;
92                 if (h == 1)
93                         v = -v;
94                 return v;
95         }
96
97         public AltosMapPos(AltosUI in_owner,
98                            String label_value,
99                            String[] hemi_names,
100                            double default_value) {
101                 super(BoxLayout.X_AXIS);
102                 owner = in_owner;
103                 label = new JLabel(label_value);
104                 hemi = new JComboBox(hemi_names);
105                 hemi.setEditable(false);
106                 deg = new JTextField(5);
107                 deg.setMinimumSize(deg.getPreferredSize());
108                 deg.setHorizontalAlignment(JTextField.RIGHT);
109                 deg_label = new JLabel("°");
110                 min = new JTextField(9);
111                 min.setMinimumSize(min.getPreferredSize());
112                 min_label = new JLabel("'");
113                 set_value(default_value);
114                 add(label);
115                 add(Box.createRigidArea(new Dimension(5, 0)));
116                 add(hemi);
117                 add(Box.createRigidArea(new Dimension(5, 0)));
118                 add(deg);
119                 add(Box.createRigidArea(new Dimension(5, 0)));
120                 add(deg_label);
121                 add(Box.createRigidArea(new Dimension(5, 0)));
122                 add(min);
123                 add(Box.createRigidArea(new Dimension(5, 0)));
124                 add(min_label);
125         }
126 }
127
128 class AltosSite {
129         String  name;
130         double  latitude;
131         double  longitude;
132
133         public String toString() {
134                 return name;
135         }
136
137         public AltosSite(String in_name, double in_latitude, double in_longitude) {
138                 name = in_name;
139                 latitude = in_latitude;
140                 longitude = in_longitude;
141         }
142
143         public AltosSite(String line) throws ParseException {
144                 String[]        elements = line.split(":");
145
146                 if (elements.length < 3)
147                         throw new ParseException(String.format("Invalid site line %s", line), 0);
148
149                 name = elements[0];
150
151                 try {
152                         latitude = Double.parseDouble(elements[1]);
153                         longitude = Double.parseDouble(elements[2]);
154                 } catch (NumberFormatException ne) {
155                         throw new ParseException(String.format("Invalid site line %s", line), 0);
156                 }
157         }
158 }
159
160 class AltosSites extends Thread {
161         AltosSiteMapPreload     preload;
162         URL                     url;
163         LinkedList<AltosSite>   sites;
164
165         void notify_complete() {
166                 SwingUtilities.invokeLater(new Runnable() {
167                                 public void run() {
168                                         preload.set_sites();
169                                 }
170                         });
171         }
172
173         void add(AltosSite site) {
174                 sites.add(site);
175         }
176
177         void add(String line) {
178                 try {
179                         add(new AltosSite(line));
180                 } catch (ParseException pe) {
181                 }
182         }
183
184         public void run() {
185                 try {
186                         URLConnection uc = url.openConnection();
187                         int length = uc.getContentLength();
188                         
189                         InputStreamReader in_stream = new InputStreamReader(uc.getInputStream(), Altos.unicode_set);
190                         BufferedReader in = new BufferedReader(in_stream);
191
192                         for (;;) {
193                                 String line = in.readLine();
194                                 if (line == null)
195                                         break;
196                                 add(line);
197                         }
198                 } catch (IOException e) {
199                 } finally {
200                         notify_complete();
201                 }
202         }
203
204         public AltosSites(AltosSiteMapPreload in_preload) {
205                 sites = new LinkedList<AltosSite>();
206                 preload = in_preload;
207                 try {
208                         url = new URL(Altos.launch_sites_url);
209                 } catch (java.net.MalformedURLException e) {
210                         notify_complete();
211                 }
212                 start();
213         }
214 }
215
216 public class AltosSiteMapPreload extends AltosDialog implements ActionListener, ItemListener {
217         AltosUI         owner;
218         AltosSiteMap    map;
219
220         AltosMapPos     lat;
221         AltosMapPos     lon;
222
223         final static int        radius = 4;
224         final static int        width = (radius * 2 + 1);
225         final static int        height = (radius * 2 + 1);
226
227         JProgressBar    pbar;
228
229         AltosSites      sites;
230         JLabel          site_list_label;
231         JComboBox       site_list;
232                 
233         JToggleButton   load_button;
234         boolean         loading;
235         JButton         close_button;
236
237         static final String[]   lat_hemi_names = { "N", "S" };
238         static final String[]   lon_hemi_names = { "E", "W" };
239
240         class updatePbar implements Runnable {
241                 int             n;
242                 String          s;
243
244                 public updatePbar(int x, int y, String in_s) {
245                         n = (x + radius) + (y + radius) * width + 1;
246                         s = in_s;
247                 }
248
249                 public void run() {
250                         pbar.setValue(n);
251                         pbar.setString(s);
252                         if (n < width * height) {
253                                 pbar.setValue(n);
254                                 pbar.setString(s);
255                         } else {
256                                 pbar.setValue(0);
257                                 pbar.setString("");
258                                 load_button.setSelected(false);
259                                 loading = false;
260                         }
261                 }
262         }
263
264         class bgLoad extends Thread {
265
266                 AltosSiteMap    map;
267
268                 public bgLoad(AltosSiteMap in_map) {
269                         map = in_map;
270                 }
271
272                 public void run() {
273                         for (int y = -map.radius; y <= map.radius; y++) {
274                                 for (int x = -map.radius; x <= map.radius; x++) {
275                                         String  pngfile;
276                                         pngfile = map.initMap(new Point(x,y));
277                                         SwingUtilities.invokeLater(new updatePbar(x, y, pngfile));
278                                 }
279                         }
280                 }
281         }
282
283         public void set_sites() {
284                 int     i = 1;
285                 for (AltosSite site : sites.sites) {
286                         site_list.insertItemAt(site, i);
287                         i++;
288                 }
289         }
290
291         public void itemStateChanged(ItemEvent e) {
292                 int             state = e.getStateChange();
293
294                 if (state == ItemEvent.SELECTED) {
295                         Object  o = e.getItem();
296                         if (o instanceof AltosSite) {
297                                 AltosSite       site = (AltosSite) o;
298                                 lat.set_value(site.latitude);
299                                 lon.set_value(site.longitude);
300                         }
301                 }
302         }
303
304         public void actionPerformed(ActionEvent e) {
305                 String  cmd = e.getActionCommand();
306
307                 if (cmd.equals("close"))
308                         setVisible(false);
309
310                 if (cmd.equals("load")) {
311                         if (!loading) {
312                                 try {
313                                         final double    latitude = lat.get_value();
314                                         final double    longitude = lon.get_value();
315                                         map.setBaseLocation(latitude,longitude);
316                                         map.draw_circle(latitude,longitude);
317                                         loading = true;
318                                         bgLoad thread = new bgLoad(map);
319                                         thread.start();
320                                 } catch (NumberFormatException ne) {
321                                         load_button.setSelected(false);
322                                 }
323                         }
324                 }
325         }
326
327         public AltosSiteMapPreload(AltosUI in_owner) {
328                 owner = in_owner;
329
330                 Container               pane = getContentPane();
331                 GridBagConstraints      c = new GridBagConstraints();
332                 Insets                  i = new Insets(4,4,4,4);
333
334                 pane.setLayout(new GridBagLayout());
335
336                 map = new AltosSiteMap(4);
337
338                 c.fill = GridBagConstraints.BOTH;
339                 c.anchor = GridBagConstraints.CENTER;
340                 c.insets = i;
341                 c.weightx = 1;
342                 c.weighty = 1;
343
344                 c.gridx = 0;
345                 c.gridy = 0;
346                 c.gridwidth = 2;
347                 c.anchor = GridBagConstraints.CENTER;
348
349                 pane.add(map, c);
350
351                 pbar = new JProgressBar();
352                 pbar.setMinimum(0);
353                 pbar.setMaximum(width * height);
354                 pbar.setValue(0);
355                 pbar.setString("");
356                 pbar.setStringPainted(true);
357                 
358                 c.fill = GridBagConstraints.HORIZONTAL;
359                 c.anchor = GridBagConstraints.CENTER;
360                 c.insets = i;
361                 c.weightx = 1;
362                 c.weighty = 0;
363
364                 c.gridx = 0;
365                 c.gridy = 1;
366                 c.gridwidth = 2;
367
368                 pane.add(pbar, c);
369
370                 site_list_label = new JLabel ("Known Launch Sites:");
371
372                 c.fill = GridBagConstraints.NONE;
373                 c.anchor = GridBagConstraints.CENTER;
374                 c.insets = i;
375                 c.weightx = 1;
376                 c.weighty = 0;
377
378                 c.gridx = 0;
379                 c.gridy = 2;
380                 c.gridwidth = 1;
381
382                 pane.add(site_list_label, c);
383                 
384                 site_list = new JComboBox(new String[] { "Site List" });
385                 site_list.addItemListener(this);
386
387                 sites = new AltosSites(this);
388
389                 c.fill = GridBagConstraints.HORIZONTAL;
390                 c.anchor = GridBagConstraints.CENTER;
391                 c.insets = i;
392                 c.weightx = 1;
393                 c.weighty = 0;
394
395                 c.gridx = 1;
396                 c.gridy = 2;
397                 c.gridwidth = 1;
398
399                 pane.add(site_list, c);
400                 
401                 lat = new AltosMapPos(owner,
402                                       "Latitude:",
403                                       lat_hemi_names,
404                                       37.167833333);
405                 c.fill = GridBagConstraints.NONE;
406                 c.anchor = GridBagConstraints.CENTER;
407                 c.insets = i;
408                 c.weightx = 0;
409                 c.weighty = 0;
410
411                 c.gridx = 0;
412                 c.gridy = 3;
413                 c.gridwidth = 1;
414                 c.anchor = GridBagConstraints.CENTER;
415
416                 pane.add(lat, c);
417                 
418                 lon = new AltosMapPos(owner,
419                                       "Longitude:",
420                                       lon_hemi_names,
421                                       -97.73975);
422
423                 c.fill = GridBagConstraints.NONE;
424                 c.anchor = GridBagConstraints.CENTER;
425                 c.insets = i;
426                 c.weightx = 0;
427                 c.weighty = 0;
428
429                 c.gridx = 1;
430                 c.gridy = 3;
431                 c.gridwidth = 1;
432                 c.anchor = GridBagConstraints.CENTER;
433
434                 pane.add(lon, c);
435
436                 load_button = new JToggleButton("Load Map");
437                 load_button.addActionListener(this);
438                 load_button.setActionCommand("load");
439                 
440                 c.fill = GridBagConstraints.NONE;
441                 c.anchor = GridBagConstraints.CENTER;
442                 c.insets = i;
443                 c.weightx = 1;
444                 c.weighty = 0;
445
446                 c.gridx = 0;
447                 c.gridy = 4;
448                 c.gridwidth = 1;
449                 c.anchor = GridBagConstraints.CENTER;
450
451                 pane.add(load_button, c);
452
453                 close_button = new JButton("Close");
454                 close_button.addActionListener(this);
455                 close_button.setActionCommand("close");
456                 
457                 c.fill = GridBagConstraints.NONE;
458                 c.anchor = GridBagConstraints.CENTER;
459                 c.insets = i;
460                 c.weightx = 1;
461                 c.weighty = 0;
462
463                 c.gridx = 1;
464                 c.gridy = 4;
465                 c.gridwidth = 1;
466                 c.anchor = GridBagConstraints.CENTER;
467
468                 pane.add(close_button, c);
469
470                 pack();
471                 setLocationRelativeTo(owner);
472                 setVisible(true);
473         }
474 }