altosui: Display full map preload area in view.
[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                 add(label);
109                 add(Box.createRigidArea(new Dimension(5, 0)));
110                 add(hemi);
111                 add(Box.createRigidArea(new Dimension(5, 0)));
112                 add(deg);
113                 add(Box.createRigidArea(new Dimension(5, 0)));
114                 add(deg_label);
115                 add(Box.createRigidArea(new Dimension(5, 0)));
116                 add(min);
117                 add(Box.createRigidArea(new Dimension(5, 0)));
118                 add(min_label);
119         }
120 }
121
122 public class AltosSiteMapPreload extends JDialog implements ActionListener {
123         AltosUI         owner;
124         AltosSiteMap    map;
125
126         AltosMapPos     lat;
127         AltosMapPos     lon;
128
129         JProgressBar    pbar;
130
131         final static int        radius = 4;
132         final static int        width = (radius * 2 + 1);
133         final static int        height = (radius * 2 + 1);
134
135         JToggleButton   load_button;
136         boolean         loading;
137         JButton         close_button;
138
139         static final String[]   lat_hemi_names = { "N", "S" };
140         static final String[]   lon_hemi_names = { "E", "W" };
141
142         class updatePbar implements Runnable {
143                 int             n;
144                 String          s;
145
146                 public updatePbar(int x, int y, String in_s) {
147                         n = (x + radius) + (y + radius) * width + 1;
148                         System.out.printf("update pbar %d\n", n);
149                         s = in_s;
150                 }
151
152                 public void run() {
153                         pbar.setValue(n);
154                         pbar.setString(s);
155                         if (n < width * height) {
156                                 pbar.setValue(n);
157                                 pbar.setString(s);
158                         } else {
159                                 pbar.setValue(0);
160                                 pbar.setString("");
161                                 load_button.setSelected(false);
162                                 loading = false;
163                         }
164                 }
165         }
166
167         class bgLoad extends Thread {
168
169                 AltosSiteMap    map;
170
171                 public bgLoad(AltosSiteMap in_map) {
172                         map = in_map;
173                 }
174
175                 public void run() {
176                         for (int y = -map.radius; y <= map.radius; y++) {
177                                 for (int x = -map.radius; x <= map.radius; x++) {
178                                         String  pngfile;
179                                         pngfile = map.initMap(new Point(x,y));
180                                         SwingUtilities.invokeLater(new updatePbar(x, y, pngfile));
181                                 }
182                         }
183                 }
184         }
185
186         public void actionPerformed(ActionEvent e) {
187                 String  cmd = e.getActionCommand();
188
189                 if (cmd.equals("close"))
190                         setVisible(false);
191
192                 if (cmd.equals("load")) {
193                         if (!loading) {
194                                 try {
195                                         final double    latitude = lat.get_value();
196                                         final double    longitude = lon.get_value();
197                                         map.setBaseLocation(latitude,longitude);
198                                         loading = true;
199                                         bgLoad thread = new bgLoad(map);
200                                         thread.start();
201                                 } catch (NumberFormatException ne) {
202                                         load_button.setSelected(false);
203                                 }
204                         }
205                 }
206         }
207
208         public AltosSiteMapPreload(AltosUI in_owner) {
209                 owner = in_owner;
210
211                 Container               pane = getContentPane();
212                 GridBagConstraints      c = new GridBagConstraints();
213                 Insets                  i = new Insets(4,4,4,4);
214
215                 pane.setLayout(new GridBagLayout());
216
217                 map = new AltosSiteMap(4);
218
219                 c.fill = GridBagConstraints.BOTH;
220                 c.anchor = GridBagConstraints.CENTER;
221                 c.insets = i;
222                 c.weightx = 1;
223                 c.weighty = 1;
224
225                 c.gridx = 0;
226                 c.gridy = 0;
227                 c.gridwidth = 2;
228                 c.anchor = GridBagConstraints.CENTER;
229
230                 pane.add(map, c);
231
232                 pbar = new JProgressBar();
233                 pbar.setMinimum(0);
234                 pbar.setMaximum(width * height);
235                 pbar.setValue(0);
236                 pbar.setString("");
237                 pbar.setStringPainted(true);
238                 
239                 c.fill = GridBagConstraints.HORIZONTAL;
240                 c.anchor = GridBagConstraints.CENTER;
241                 c.insets = i;
242                 c.weightx = 1;
243                 c.weighty = 0;
244
245                 c.gridx = 0;
246                 c.gridy = 1;
247                 c.gridwidth = 2;
248
249                 pane.add(pbar, c);
250
251                 lat = new AltosMapPos(owner,
252                                       "Latitude:",
253                                       lat_hemi_names,
254                                       37.167833333);
255                 c.fill = GridBagConstraints.NONE;
256                 c.anchor = GridBagConstraints.CENTER;
257                 c.insets = i;
258                 c.weightx = 0;
259                 c.weighty = 0;
260
261                 c.gridx = 0;
262                 c.gridy = 2;
263                 c.gridwidth = 1;
264                 c.anchor = GridBagConstraints.CENTER;
265
266                 pane.add(lat, c);
267                 
268                 lon = new AltosMapPos(owner,
269                                       "Longitude:",
270                                       lon_hemi_names,
271                                       -97.73975);
272
273                 c.fill = GridBagConstraints.NONE;
274                 c.anchor = GridBagConstraints.CENTER;
275                 c.insets = i;
276                 c.weightx = 0;
277                 c.weighty = 0;
278
279                 c.gridx = 1;
280                 c.gridy = 2;
281                 c.gridwidth = 1;
282                 c.anchor = GridBagConstraints.CENTER;
283
284                 pane.add(lon, c);
285
286                 load_button = new JToggleButton("Load Map");
287                 load_button.addActionListener(this);
288                 load_button.setActionCommand("load");
289                 
290                 c.fill = GridBagConstraints.NONE;
291                 c.anchor = GridBagConstraints.CENTER;
292                 c.insets = i;
293                 c.weightx = 1;
294                 c.weighty = 0;
295
296                 c.gridx = 0;
297                 c.gridy = 3;
298                 c.gridwidth = 1;
299                 c.anchor = GridBagConstraints.CENTER;
300
301                 pane.add(load_button, c);
302
303                 close_button = new JButton("Close");
304                 close_button.addActionListener(this);
305                 close_button.setActionCommand("close");
306                 
307                 c.fill = GridBagConstraints.NONE;
308                 c.anchor = GridBagConstraints.CENTER;
309                 c.insets = i;
310                 c.weightx = 1;
311                 c.weighty = 0;
312
313                 c.gridx = 1;
314                 c.gridy = 3;
315                 c.gridwidth = 1;
316                 c.anchor = GridBagConstraints.CENTER;
317
318                 pane.add(close_button, c);
319
320                 pack();
321                 setLocationRelativeTo(owner);
322                 setVisible(true);
323         }
324 }